diff --git a/src/apps/exactly/common/exactly.definitions-resolver.ts b/src/apps/exactly/common/exactly.definitions-resolver.ts index 996d8fdd1..27beb783c 100644 --- a/src/apps/exactly/common/exactly.definitions-resolver.ts +++ b/src/apps/exactly/common/exactly.definitions-resolver.ts @@ -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>; -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 }) { diff --git a/src/apps/exactly/common/exactly.fixed-position-fetcher.ts b/src/apps/exactly/common/exactly.fixed-position-fetcher.ts index df1da2bd2..c83d9e8c2 100644 --- a/src/apps/exactly/common/exactly.fixed-position-fetcher.ts +++ b/src/apps/exactly/common/exactly.fixed-position-fetcher.ts @@ -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 }; @@ -40,12 +36,14 @@ export abstract class ExactlyFixedPositionFetcher< }; getApr(params: GetDataPropsParams) { - return Number(this.getBestRate(params).rate) / 1e18; + return Number(this.getBestRate(params).rate) / 1e16; } getApy(params: GetDataPropsParams) { 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, + ); } } diff --git a/src/apps/exactly/common/exactly.token-fetcher.ts b/src/apps/exactly/common/exactly.token-fetcher.ts index 5f4de6a6b..3f92583e3 100644 --- a/src/apps/exactly/common/exactly.token-fetcher.ts +++ b/src/apps/exactly/common/exactly.token-fetcher.ts @@ -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'; @@ -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 }; @@ -53,7 +49,7 @@ export abstract class ExactlyTokenFetcher< } getUnderlyingTokenDefinitions({ definition }: GetUnderlyingTokensParams) { - return Promise.resolve([{ address: definition.asset, network: this.network }]); + return Promise.resolve([{ address: definition.asset.toLowerCase(), network: this.network }]); } getSymbol({ definition }: GetTokenPropsParams) { @@ -84,7 +80,7 @@ export abstract class ExactlyTokenFetcher< } async getApy(params: GetDataPropsParams) { - 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) { diff --git a/src/apps/exactly/contracts/abis/previewer.json b/src/apps/exactly/contracts/abis/previewer.json index e1d330963..7680f9ebd 100644 --- a/src/apps/exactly/contracts/abis/previewer.json +++ b/src/apps/exactly/contracts/abis/previewer.json @@ -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": [ @@ -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" }, @@ -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" }, @@ -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" } diff --git a/src/apps/exactly/contracts/ethers/Previewer.ts b/src/apps/exactly/contracts/ethers/Previewer.ts index ada695173..6a2e8e7cd 100644 --- a/src/apps/exactly/contracts/ethers/Previewer.ts +++ b/src/apps/exactly/contracts/ethers/Previewer.ts @@ -92,6 +92,7 @@ export declare namespace Previewer { symbol: PromiseOrValue; decimals: PromiseOrValue; asset: PromiseOrValue; + assetName: PromiseOrValue; assetSymbol: PromiseOrValue; interestRateModel: Previewer.InterestRateModelStruct; usdPrice: PromiseOrValue; @@ -99,6 +100,8 @@ export declare namespace Previewer { adjustFactor: PromiseOrValue; maxFuturePools: PromiseOrValue; fixedPools: Previewer.FixedPoolStruct[]; + floatingBorrowRate: PromiseOrValue; + floatingUtilization: PromiseOrValue; floatingBackupBorrowed: PromiseOrValue; floatingAvailableAssets: PromiseOrValue; totalFloatingBorrowAssets: PromiseOrValue; @@ -121,6 +124,7 @@ export declare namespace Previewer { number, string, string, + string, Previewer.InterestRateModelStructOutput, BigNumber, BigNumber, @@ -133,6 +137,8 @@ export declare namespace Previewer { BigNumber, BigNumber, BigNumber, + BigNumber, + BigNumber, boolean, BigNumber, BigNumber, @@ -146,6 +152,7 @@ export declare namespace Previewer { symbol: string; decimals: number; asset: string; + assetName: string; assetSymbol: string; interestRateModel: Previewer.InterestRateModelStructOutput; usdPrice: BigNumber; @@ -153,6 +160,8 @@ export declare namespace Previewer { adjustFactor: BigNumber; maxFuturePools: number; fixedPools: Previewer.FixedPoolStructOutput[]; + floatingBorrowRate: BigNumber; + floatingUtilization: BigNumber; floatingBackupBorrowed: BigNumber; floatingAvailableAssets: BigNumber; totalFloatingBorrowAssets: BigNumber; @@ -347,15 +356,15 @@ export interface Previewer extends BaseContract { positionAssets: PromiseOrValue, borrower: PromiseOrValue, overrides?: CallOverrides, - ): Promise<[BigNumber] & { repayAssets: BigNumber }>; + ): Promise<[Previewer.FixedPreviewStructOutput]>; previewWithdrawAtMaturity( market: PromiseOrValue, maturity: PromiseOrValue, positionAssets: PromiseOrValue, - arg3: PromiseOrValue, + owner: PromiseOrValue, overrides?: CallOverrides, - ): Promise<[BigNumber] & { withdrawAssets: BigNumber }>; + ): Promise<[Previewer.FixedPreviewStructOutput]>; }; auditor(overrides?: CallOverrides): Promise; @@ -396,15 +405,15 @@ export interface Previewer extends BaseContract { positionAssets: PromiseOrValue, borrower: PromiseOrValue, overrides?: CallOverrides, - ): Promise; + ): Promise; previewWithdrawAtMaturity( market: PromiseOrValue, maturity: PromiseOrValue, positionAssets: PromiseOrValue, - arg3: PromiseOrValue, + owner: PromiseOrValue, overrides?: CallOverrides, - ): Promise; + ): Promise; callStatic: { auditor(overrides?: CallOverrides): Promise; @@ -445,15 +454,15 @@ export interface Previewer extends BaseContract { positionAssets: PromiseOrValue, borrower: PromiseOrValue, overrides?: CallOverrides, - ): Promise; + ): Promise; previewWithdrawAtMaturity( market: PromiseOrValue, maturity: PromiseOrValue, positionAssets: PromiseOrValue, - arg3: PromiseOrValue, + owner: PromiseOrValue, overrides?: CallOverrides, - ): Promise; + ): Promise; }; filters: {}; @@ -503,7 +512,7 @@ export interface Previewer extends BaseContract { market: PromiseOrValue, maturity: PromiseOrValue, positionAssets: PromiseOrValue, - arg3: PromiseOrValue, + owner: PromiseOrValue, overrides?: CallOverrides, ): Promise; }; @@ -553,7 +562,7 @@ export interface Previewer extends BaseContract { market: PromiseOrValue, maturity: PromiseOrValue, positionAssets: PromiseOrValue, - arg3: PromiseOrValue, + owner: PromiseOrValue, overrides?: CallOverrides, ): Promise; }; diff --git a/src/apps/exactly/contracts/ethers/factories/Previewer__factory.ts b/src/apps/exactly/contracts/ethers/factories/Previewer__factory.ts index cc836b703..1e5538241 100644 --- a/src/apps/exactly/contracts/ethers/factories/Previewer__factory.ts +++ b/src/apps/exactly/contracts/ethers/factories/Previewer__factory.ts @@ -86,6 +86,11 @@ const _abi = [ name: 'asset', type: 'address', }, + { + internalType: 'string', + name: 'assetName', + type: 'string', + }, { internalType: 'string', name: 'assetSymbol', @@ -200,6 +205,16 @@ const _abi = [ name: 'fixedPools', type: 'tuple[]', }, + { + internalType: 'uint256', + name: 'floatingBorrowRate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'floatingUtilization', + type: 'uint256', + }, { internalType: 'uint256', name: 'floatingBackupBorrowed', @@ -537,9 +552,26 @@ const _abi = [ name: 'previewRepayAtMaturity', outputs: [ { - internalType: 'uint256', - name: 'repayAssets', - type: 'uint256', + 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', @@ -564,16 +596,33 @@ const _abi = [ }, { internalType: 'address', - name: '', + name: 'owner', type: 'address', }, ], name: 'previewWithdrawAtMaturity', outputs: [ { - internalType: 'uint256', - name: 'withdrawAssets', - type: 'uint256', + 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', diff --git a/src/apps/exactly/ethereum/exactly.borrow.token-fetcher.ts b/src/apps/exactly/ethereum/exactly.borrow.token-fetcher.ts index db83dbe28..1db2f6e5d 100644 --- a/src/apps/exactly/ethereum/exactly.borrow.token-fetcher.ts +++ b/src/apps/exactly/ethereum/exactly.borrow.token-fetcher.ts @@ -1,13 +1,10 @@ -import { constants } from 'ethers'; - import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; import type { IMulticallWrapper } from '~multicall/multicall.interface'; import type { AppTokenPosition } from '~position/position.interface'; import type { GetDataPropsParams, GetTokenPropsParams } from '~position/template/app-token.template.types'; import type { ExactlyMarketDefinition } from '../common/exactly.definitions-resolver'; -import { ExactlyTokenFetcher } from '../common/exactly.token-fetcher'; -import type { ExactlyMarketProps } from '../common/exactly.token-fetcher'; +import { type ExactlyMarketProps, ExactlyTokenFetcher } from '../common/exactly.token-fetcher'; import type { Market } from '../contracts'; @PositionTemplate() @@ -23,6 +20,10 @@ export class EthereumExactlyBorrowFetcher extends ExactlyTokenFetcher { return definition.totalFloatingBorrowAssets; } + getApr({ definition }: GetDataPropsParams) { + return Number(definition.floatingBorrowRate) / 1e16; + } + async getBalancePerToken({ address, appToken, @@ -40,20 +41,4 @@ export class EthereumExactlyBorrowFetcher extends ExactlyTokenFetcher { }); return floatingBorrowShares; } - - async getApr({ - contract, - multicall, - definition: { interestRateModel }, - }: GetDataPropsParams) { - const [debt, assets, utilization] = await Promise.all([ - contract.floatingDebt(), - contract.floatingAssets(), - contract.floatingUtilization(), - ]); - const rate = await multicall - .wrap(this.contractFactory.interestRateModel({ address: interestRateModel.id, network: this.network })) - .floatingBorrowRate(utilization, assets.isZero() ? 0 : debt.mul(constants.WeiPerEther).div(assets)); - return Number(rate) / 1e18; - } } diff --git a/src/apps/exactly/ethereum/exactly.deposit.token-fetcher.ts b/src/apps/exactly/ethereum/exactly.deposit.token-fetcher.ts index 5475ec034..4e4fc05a3 100644 --- a/src/apps/exactly/ethereum/exactly.deposit.token-fetcher.ts +++ b/src/apps/exactly/ethereum/exactly.deposit.token-fetcher.ts @@ -1,9 +1,10 @@ +import { type BigNumber, constants } from 'ethers'; + import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; -import type { GetTokenPropsParams } from '~position/template/app-token.template.types'; +import type { GetDataPropsParams, GetTokenPropsParams } from '~position/template/app-token.template.types'; import type { ExactlyMarketDefinition } from '../common/exactly.definitions-resolver'; -import { ExactlyTokenFetcher } from '../common/exactly.token-fetcher'; -import type { ExactlyMarketProps } from '../common/exactly.token-fetcher'; +import { type ExactlyMarketProps, ExactlyTokenFetcher } from '../common/exactly.token-fetcher'; import type { Market } from '../contracts'; @PositionTemplate() @@ -17,4 +18,28 @@ export class EthereumExactlyDepositFetcher extends ExactlyTokenFetcher { getTotalAssets({ definition }: GetTokenPropsParams) { return definition.totalFloatingDepositAssets; } + + async getApr({ + definition: { blockNumber, timestamp, totalFloatingDepositShares, totalFloatingDepositAssets }, + multicall: { contract: multicall }, + contract: market, + }: GetDataPropsParams) { + const [, [[, totalSupplyData], [, totalAssetsData], [, tsData]]] = await multicall.callStatic.aggregate( + [ + { target: market.address, callData: market.interface.encodeFunctionData('totalSupply') }, + { target: market.address, callData: market.interface.encodeFunctionData('totalAssets') }, + { target: multicall.address, callData: multicall.interface.encodeFunctionData('getCurrentBlockTimestamp') }, + ], + true, + { blockTag: blockNumber - 123 }, + ); + const [prevTotalSupply] = market.interface.decodeFunctionResult('totalSupply', totalSupplyData) as [BigNumber]; + const [prevTotalAssets] = market.interface.decodeFunctionResult('totalAssets', totalAssetsData) as [BigNumber]; + const [prevTimestamp] = multicall.interface.decodeFunctionResult('getCurrentBlockTimestamp', tsData) as [BigNumber]; + + const shareValue = totalFloatingDepositAssets.mul(constants.WeiPerEther).div(totalFloatingDepositShares); + const prevShareValue = prevTotalAssets.mul(constants.WeiPerEther).div(prevTotalSupply); + const proportion = shareValue.mul(constants.WeiPerEther).div(prevShareValue); + return (Number(proportion) / 1e16 - 100) * (31_536_000 / (timestamp - prevTimestamp.toNumber())); + } } diff --git a/src/apps/exactly/ethereum/exactly.fixed-borrow.token-fetcher.ts b/src/apps/exactly/ethereum/exactly.fixed-borrow.token-fetcher.ts index 8c162084d..94566041a 100644 --- a/src/apps/exactly/ethereum/exactly.fixed-borrow.token-fetcher.ts +++ b/src/apps/exactly/ethereum/exactly.fixed-borrow.token-fetcher.ts @@ -6,8 +6,7 @@ import type { AppTokenPosition } from '~position/position.interface'; import type { GetDataPropsParams, GetTokenPropsParams } from '~position/template/app-token.template.types'; import type { ExactlyMarketDefinition } from '../common/exactly.definitions-resolver'; -import { ExactlyFixedPositionFetcher } from '../common/exactly.fixed-position-fetcher'; -import type { ExactlyFixedMarketProps } from '../common/exactly.fixed-position-fetcher'; +import { type ExactlyFixedMarketProps, ExactlyFixedPositionFetcher } from '../common/exactly.fixed-position-fetcher'; import type { ExactlyMarketProps } from '../common/exactly.token-fetcher'; import type { Market } from '../contracts'; diff --git a/src/apps/exactly/ethereum/exactly.fixed-deposit.token-fetcher.ts b/src/apps/exactly/ethereum/exactly.fixed-deposit.token-fetcher.ts index 330ee6a08..c829e5d74 100644 --- a/src/apps/exactly/ethereum/exactly.fixed-deposit.token-fetcher.ts +++ b/src/apps/exactly/ethereum/exactly.fixed-deposit.token-fetcher.ts @@ -6,8 +6,7 @@ import type { AppTokenPosition } from '~position/position.interface'; import type { GetDataPropsParams, GetTokenPropsParams } from '~position/template/app-token.template.types'; import type { ExactlyMarketDefinition } from '../common/exactly.definitions-resolver'; -import { ExactlyFixedPositionFetcher } from '../common/exactly.fixed-position-fetcher'; -import type { ExactlyFixedMarketProps } from '../common/exactly.fixed-position-fetcher'; +import { type ExactlyFixedMarketProps, ExactlyFixedPositionFetcher } from '../common/exactly.fixed-position-fetcher'; import type { ExactlyMarketProps } from '../common/exactly.token-fetcher'; import type { Market } from '../contracts'; diff --git a/src/apps/exactly/exactly.definition.ts b/src/apps/exactly/exactly.definition.ts index 22664e77d..7d4db6f48 100644 --- a/src/apps/exactly/exactly.definition.ts +++ b/src/apps/exactly/exactly.definition.ts @@ -5,9 +5,9 @@ import { Network } from '~types/network.interface'; export const EXACTLY_DEFINITION = appDefinition({ id: 'exactly', - name: 'Exactly Protocol', + name: 'Exactly', description: - 'Exactly is a decentralized, non-custodial and open-source protocol that provides an autonomous fixed and variable interest rate market enabling users to frictionlessly exchange the time value of their assets and completing the DeFi credit market.', + "Exactly is a decentralized, non-custodial, open-source protocol that provides an autonomous fixed and variable interest rate market, enabling users to frictionlessly exchange their assets' time value and complete the DeFi credit market.", url: 'https://app.exact.ly', tags: [AppTag.LENDING],