From fae4355edb6c80e67235446e82d609f8bc784ea4 Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 15:33:24 +0300 Subject: [PATCH 01/22] cleanup --- .../frontend/src/hooks/aave/useAaveBorrow.tsx | 19 +++++++++--------- apps/frontend/src/hooks/aave/useAaveRepay.tsx | 20 +++++++++++++------ .../frontend/src/hooks/aave/useAaveSupply.tsx | 11 +++++++--- .../src/hooks/aave/useAaveWithdraw.tsx | 5 +---- apps/frontend/src/types/aave.ts | 5 +++++ .../aave/AaveBorrowTransactionsFactory.ts | 15 +++++++------- .../aave/AaveRepayTransactionsFactory.ts | 10 ++++++++-- .../aave/AaveWithdrawTransactionsFactory.ts | 14 ++++++++++--- 8 files changed, 65 insertions(+), 34 deletions(-) diff --git a/apps/frontend/src/hooks/aave/useAaveBorrow.tsx b/apps/frontend/src/hooks/aave/useAaveBorrow.tsx index a930a42f4..8ffcf74e6 100644 --- a/apps/frontend/src/hooks/aave/useAaveBorrow.tsx +++ b/apps/frontend/src/hooks/aave/useAaveBorrow.tsx @@ -9,16 +9,11 @@ import { Decimal } from '@sovryn/utils'; import { config } from '../../constants/aave'; import { useTransactionContext } from '../../contexts/TransactionContext'; import { translations } from '../../locales/i18n'; -import { - AaveBorrowTransactionsFactory, - BorrowRateMode, -} from '../../utils/aave/AaveBorrowTransactionsFactory'; +import { BorrowRateMode, TransactionFactoryOptions } from '../../types/aave'; +import { AaveBorrowTransactionsFactory } from '../../utils/aave/AaveBorrowTransactionsFactory'; import { useAccount } from '../useAccount'; -export const useAaveBorrow = (props: { - onBegin?: () => void; - onComplete?: () => void; -}) => { +export const useAaveBorrow = () => { const { signer } = useAccount(); const { setTransactions, setIsOpen, setTitle } = useTransactionContext(); @@ -37,6 +32,7 @@ export const useAaveBorrow = (props: { amount: Decimal, asset: AssetDetailsData, rateMode: BorrowRateMode, + opts?: TransactionFactoryOptions, ) => { if (!aaveBorrowTransactionsFactory) { return; @@ -46,7 +42,12 @@ export const useAaveBorrow = (props: { ); setTransactions( - await aaveBorrowTransactionsFactory.borrow(asset, bnAmount, rateMode), + await aaveBorrowTransactionsFactory.borrow( + asset, + bnAmount, + rateMode, + opts, + ), ); setTitle(t(translations.aavePage.common.borrow)); setIsOpen(true); diff --git a/apps/frontend/src/hooks/aave/useAaveRepay.tsx b/apps/frontend/src/hooks/aave/useAaveRepay.tsx index 6bd2ff40e..164c843a3 100644 --- a/apps/frontend/src/hooks/aave/useAaveRepay.tsx +++ b/apps/frontend/src/hooks/aave/useAaveRepay.tsx @@ -9,14 +9,12 @@ import { Decimal } from '@sovryn/utils'; import { config } from '../../constants/aave'; import { useTransactionContext } from '../../contexts/TransactionContext'; import { translations } from '../../locales/i18n'; +import { TransactionFactoryOptions } from '../../types/aave'; import { AaveRepayTransactionsFactory } from '../../utils/aave/AaveRepayTransactionsFactory'; import { LoanType } from '../../utils/aave/AaveUserReservesSummary'; import { useAccount } from '../useAccount'; -export const useAaveRepay = (props: { - onBegin?: () => void; - onComplete?: () => void; -}) => { +export const useAaveRepay = () => { const { signer } = useAccount(); const { setTransactions, setIsOpen, setTitle } = useTransactionContext(); @@ -30,7 +28,12 @@ export const useAaveRepay = (props: { }, [signer]); const handleRepay = useCallback( - async (amount: Decimal, asset: AssetDetailsData, loanType: LoanType) => { + async ( + amount: Decimal, + asset: AssetDetailsData, + loanType: LoanType, + opts?: TransactionFactoryOptions, + ) => { if (!aaveRepayTransactionsFactory) { return; } @@ -39,7 +42,12 @@ export const useAaveRepay = (props: { ); setTransactions( - await aaveRepayTransactionsFactory.repay(asset, bnAmount, loanType), + await aaveRepayTransactionsFactory.repay( + asset, + bnAmount, + loanType, + opts, + ), ); setTitle(t(translations.common.buttons.repay)); setIsOpen(true); diff --git a/apps/frontend/src/hooks/aave/useAaveSupply.tsx b/apps/frontend/src/hooks/aave/useAaveSupply.tsx index f3fb6078b..b6c604114 100644 --- a/apps/frontend/src/hooks/aave/useAaveSupply.tsx +++ b/apps/frontend/src/hooks/aave/useAaveSupply.tsx @@ -9,6 +9,7 @@ import { Decimal } from '@sovryn/utils'; import { config } from '../../constants/aave'; import { useTransactionContext } from '../../contexts/TransactionContext'; import { translations } from '../../locales/i18n'; +import { TransactionFactoryOptions } from '../../types/aave'; import { AaveSupplyTransactionsFactory } from '../../utils/aave/AaveSupplyTransactionsFactory'; import { useAccount } from '../useAccount'; @@ -26,7 +27,11 @@ export const useAaveSupply = () => { }, [signer]); const handleDeposit = useCallback( - async (amount: Decimal, asset: AssetDetailsData) => { + async ( + amount: Decimal, + asset: AssetDetailsData, + opts?: TransactionFactoryOptions, + ) => { if (!aaveSupplyTransactionsFactory) { return; } @@ -35,7 +40,7 @@ export const useAaveSupply = () => { ); setTransactions( - await aaveSupplyTransactionsFactory.supply(asset, bnAmount), + await aaveSupplyTransactionsFactory.supply(asset, bnAmount, opts), ); setTitle(t(translations.common.deposit)); setIsOpen(true); @@ -47,7 +52,7 @@ export const useAaveSupply = () => { async ( asset: AssetDetailsData, useAsCollateral: boolean, - opts?: { onComplete?: () => void }, + opts?: TransactionFactoryOptions, ) => { if (!aaveSupplyTransactionsFactory) { return; diff --git a/apps/frontend/src/hooks/aave/useAaveWithdraw.tsx b/apps/frontend/src/hooks/aave/useAaveWithdraw.tsx index e0ff36e2b..89fef327a 100644 --- a/apps/frontend/src/hooks/aave/useAaveWithdraw.tsx +++ b/apps/frontend/src/hooks/aave/useAaveWithdraw.tsx @@ -12,10 +12,7 @@ import { translations } from '../../locales/i18n'; import { AaveWithdrawTransactionsFactory } from '../../utils/aave/AaveWithdrawTransactionsFactory'; import { useAccount } from '../useAccount'; -export const useAaveWithdraw = (props: { - onBegin?: () => void; - onComplete?: () => void; -}) => { +export const useAaveWithdraw = () => { const { signer } = useAccount(); const { setTransactions, setIsOpen, setTitle } = useTransactionContext(); diff --git a/apps/frontend/src/types/aave.ts b/apps/frontend/src/types/aave.ts index ecb543681..3f43e626d 100644 --- a/apps/frontend/src/types/aave.ts +++ b/apps/frontend/src/types/aave.ts @@ -1 +1,6 @@ export type TransactionFactoryOptions = { onComplete?: () => void }; + +export enum BorrowRateMode { + STABLE = 1, + VARIABLE = 2, +} diff --git a/apps/frontend/src/utils/aave/AaveBorrowTransactionsFactory.ts b/apps/frontend/src/utils/aave/AaveBorrowTransactionsFactory.ts index 691fd3e33..e602456db 100644 --- a/apps/frontend/src/utils/aave/AaveBorrowTransactionsFactory.ts +++ b/apps/frontend/src/utils/aave/AaveBorrowTransactionsFactory.ts @@ -10,11 +10,7 @@ import { TransactionType, } from '../../app/3_organisms/TransactionStepDialog/TransactionStepDialog.types'; import { translations } from '../../locales/i18n'; - -export enum BorrowRateMode { - STABLE = 1, - VARIABLE = 2, -} +import { BorrowRateMode, TransactionFactoryOptions } from '../../types/aave'; export class AaveBorrowTransactionsFactory { private readonly Pool: ethers.Contract; @@ -54,15 +50,17 @@ export class AaveBorrowTransactionsFactory { token: AssetDetailsData, amount: BigNumber, rateMode: BorrowRateMode, + opts?: TransactionFactoryOptions, ): Promise { - if (token.isNative) return this.borrowNative(amount, rateMode); - else return this.borrowToken(token, amount, rateMode); + if (token.isNative) return this.borrowNative(amount, rateMode, opts); + else return this.borrowToken(token, amount, rateMode, opts); } private async borrowToken( asset: AssetDetailsData, amount: BigNumber, rateMode: BorrowRateMode, + opts?: TransactionFactoryOptions, ): Promise { return [ { @@ -85,6 +83,7 @@ export class AaveBorrowTransactionsFactory { contract: this.Pool, fnName: 'borrow', }, + onComplete: opts?.onComplete, }, ]; } @@ -92,6 +91,7 @@ export class AaveBorrowTransactionsFactory { private async borrowNative( amount: BigNumber, rateMode: BorrowRateMode, + opts?: TransactionFactoryOptions, ): Promise { const nativeAsset = await getAssetDataByAddress( constants.AddressZero, @@ -128,6 +128,7 @@ export class AaveBorrowTransactionsFactory { contract: this.WETHGateway, fnName: 'borrowETH', }, + onComplete: opts?.onComplete, }, ]; } diff --git a/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts b/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts index 2394cd99d..c437f1b59 100644 --- a/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts +++ b/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts @@ -10,6 +10,7 @@ import { TransactionType, } from '../../app/3_organisms/TransactionStepDialog/TransactionStepDialog.types'; import { translations } from '../../locales/i18n'; +import { TransactionFactoryOptions } from '../../types/aave'; import { LoanType } from './AaveUserReservesSummary'; export class AaveRepayTransactionsFactory { @@ -42,15 +43,17 @@ export class AaveRepayTransactionsFactory { token: AssetDetailsData, amount: BigNumber, loanType: LoanType, + opts?: TransactionFactoryOptions, ): Promise { - if (token.isNative) return this.repayNative(amount, loanType); - else return this.repayToken(token, amount, loanType); + if (token.isNative) return this.repayNative(amount, loanType, opts); + else return this.repayToken(token, amount, loanType, opts); } private async repayToken( asset: AssetDetailsData, amount: BigNumber, loanType: LoanType, + opts?: TransactionFactoryOptions, ): Promise { return [ { @@ -73,6 +76,7 @@ export class AaveRepayTransactionsFactory { fnName: 'repay', value: 0, }, + onComplete: opts?.onComplete, }, ]; } @@ -80,6 +84,7 @@ export class AaveRepayTransactionsFactory { private async repayNative( amount: BigNumber, loanType: LoanType, + opts?: TransactionFactoryOptions, ): Promise { const nativeAsset = await getAssetDataByAddress( constants.AddressZero, @@ -107,6 +112,7 @@ export class AaveRepayTransactionsFactory { fnName: 'repayETH', value: amount.toString(), }, + onComplete: opts?.onComplete, }, ]; } diff --git a/apps/frontend/src/utils/aave/AaveWithdrawTransactionsFactory.ts b/apps/frontend/src/utils/aave/AaveWithdrawTransactionsFactory.ts index 9b414af87..238c561a8 100644 --- a/apps/frontend/src/utils/aave/AaveWithdrawTransactionsFactory.ts +++ b/apps/frontend/src/utils/aave/AaveWithdrawTransactionsFactory.ts @@ -10,6 +10,7 @@ import { TransactionType, } from '../../app/3_organisms/TransactionStepDialog/TransactionStepDialog.types'; import { translations } from '../../locales/i18n'; +import { TransactionFactoryOptions } from '../../types/aave'; import { prepareApproveTransaction } from '../transactions'; export class AaveWithdrawTransactionsFactory { @@ -37,14 +38,16 @@ export class AaveWithdrawTransactionsFactory { async withdraw( token: AssetDetailsData, amount: BigNumber, + opts?: TransactionFactoryOptions, ): Promise { - if (token.isNative) return this.withdrawNative(amount); - else return this.withdrawToken(token, amount); + if (token.isNative) return this.withdrawNative(amount, opts); + else return this.withdrawToken(token, amount, opts); } private async withdrawToken( asset: AssetDetailsData, amount: BigNumber, + opts?: TransactionFactoryOptions, ): Promise { return [ { @@ -65,11 +68,15 @@ export class AaveWithdrawTransactionsFactory { contract: this.Pool, fnName: 'withdraw', }, + onComplete: opts?.onComplete, }, ]; } - private async withdrawNative(amount: BigNumber): Promise { + private async withdrawNative( + amount: BigNumber, + opts?: TransactionFactoryOptions, + ): Promise { const aWETH = await getAssetData('aWETH', BOB_CHAIN_ID); const approval = await prepareApproveTransaction({ @@ -99,6 +106,7 @@ export class AaveWithdrawTransactionsFactory { contract: this.WETHGateway, fnName: 'withdrawETH', }, + onComplete: opts?.onComplete, }); return transactions; From bc5e4527845e3c388b5a48330f9503855c3a0345 Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 15:36:10 +0300 Subject: [PATCH 02/22] fixes --- .../BorrowAssetsList/components/BorrowModal/BorrowForm.tsx | 4 ++-- .../components/RepayModal/RepayWithWalletBalanceForm.tsx | 2 +- .../components/WithdrawModal/WithdrawForm.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx index d09faab2e..b1cf7b5af 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx @@ -25,7 +25,7 @@ import { useAaveReservesData } from '../../../../../../../hooks/aave/useAaveRese import { useAaveUserReservesData } from '../../../../../../../hooks/aave/useAaveUserReservesData'; import { useDecimalAmountInput } from '../../../../../../../hooks/useDecimalAmountInput'; import { translations } from '../../../../../../../locales/i18n'; -import { BorrowRateMode } from '../../../../../../../utils/aave/AaveBorrowTransactionsFactory'; +import { BorrowRateMode } from '../../../../../../../types/aave'; import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; const pageTranslations = translations.aavePage; @@ -41,7 +41,7 @@ export const BorrowForm: FC = ({ asset }) => { const [borrowAsset, setBorrowAsset] = useState(asset); const [borrowAmount, setBorrowAmount, borrowSize] = useDecimalAmountInput(''); const [acknowledge, setAcknowledge] = useState(false); - const { handleBorrow } = useAaveBorrow({}); + const { handleBorrow } = useAaveBorrow(); const reserve = useMemo(() => { return reserves.find(r => r.symbol === borrowAsset); diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx index b1efc2e4e..a0846eaeb 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx @@ -37,7 +37,7 @@ export const RepayWithWalletBalanceForm: FC< RepayWithWalletBalanceFormProps > = ({ asset }) => { const { account } = useAccount(); - const { handleRepay } = useAaveRepay({}); + const { handleRepay } = useAaveRepay(); const reserves = useAaveReservesData(); const userReservesSummary = useAaveUserReservesData(); const [repayAsset, setRepayAsset] = useState(asset); diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawForm.tsx index ada6de14a..54a8be6cb 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawForm.tsx @@ -33,7 +33,7 @@ type WithdrawFormProps = { }; export const WithdrawForm: FC = ({ asset }) => { - const { handleWithdraw } = useAaveWithdraw({}); + const { handleWithdraw } = useAaveWithdraw(); const reserves = useAaveReservesData(); const userReservesSummary = useAaveUserReservesData(); const [withdrawAsset, setWithdrawAsset] = useState(asset); From 0dc9628d1cbfad009a965a4a6bf0f18b8697af6b Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 18:54:04 +0300 Subject: [PATCH 03/22] fixes. Connect provider. Fix repay adding proper allowance. Fix switch collateral token.address instead of token --- .../AssetAmountInput/AssetAmountInput.tsx | 3 +- .../RepayModal/RepayWithWalletBalanceForm.tsx | 2 +- .../components/AssetBalance/AssetBalance.tsx | 13 +++- apps/frontend/src/constants/aave.ts | 19 ++--- .../src/hooks/aave/useAaveReservesData.tsx | 56 +++++++++++---- .../frontend/src/hooks/aave/useAaveSupply.tsx | 2 + .../hooks/aave/useAaveUserReservesData.tsx | 71 +++++++++++++++---- .../frontend/src/locales/en/translations.json | 2 +- .../aave/AaveRepayTransactionsFactory.ts | 58 ++++++++------- .../aave/AaveSupplyTransactionsFactory.ts | 2 +- .../src/contracts/assets/bobTestnet.ts | 14 +++- 11 files changed, 171 insertions(+), 71 deletions(-) diff --git a/apps/frontend/src/app/2_molecules/AssetAmountInput/AssetAmountInput.tsx b/apps/frontend/src/app/2_molecules/AssetAmountInput/AssetAmountInput.tsx index 97ed14a9a..6d69ee9a4 100644 --- a/apps/frontend/src/app/2_molecules/AssetAmountInput/AssetAmountInput.tsx +++ b/apps/frontend/src/app/2_molecules/AssetAmountInput/AssetAmountInput.tsx @@ -59,7 +59,8 @@ export const AssetAmountInput: FC = ({ onAmountChange && onAmountChange(Decimal.from(maxAmount).toString()) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx index a0846eaeb..8ccd28ccd 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx @@ -77,7 +77,7 @@ export const RepayWithWalletBalanceForm: FC< ? debt.borrowed.gt(repayAssetBalance) ? repayAssetBalance : debt.borrowed - : Decimal.from(0); + : Decimal.from(1); }, [debt, repayAssetBalance]); const reserve = useMemo(() => { diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx index 2f8de9374..20bf29341 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx @@ -1,7 +1,10 @@ -import React, { FC } from 'react'; +import React, { FC, useEffect } from 'react'; + +import { BOB_CHAIN_ID } from '../../../../../../../config/chains'; + import { AmountRenderer } from '../../../../../../2_molecules/AmountRenderer/AmountRenderer'; -import { useAssetBalance } from '../../../../../../../hooks/useAssetBalance'; import { useAccount } from '../../../../../../../hooks/useAccount'; +import { useAssetBalance } from '../../../../../../../hooks/useAssetBalance'; export type AssetBalanceRendererProps = { asset: string; @@ -10,8 +13,12 @@ export type AssetBalanceRendererProps = { export const AssetBalanceRenderer: FC = ({ asset, }) => { - const balance = useAssetBalance(asset); const { account } = useAccount(); + const balance = useAssetBalance(asset, BOB_CHAIN_ID); + + useEffect(() => { + console.log('account', account, balance); + }, [account, balance]); return account ? ( { const provider = config.provider; // TODO: replace with useAccount + // const { provider } = useAccount(); const uiPoolDataProvider = useMemo( () => @@ -32,10 +34,40 @@ export const useAaveReservesData = (): ReserveData => { [provider], ); - const { value } = useCachedData( - 'AaveReservesData', - BOB_CHAIN_ID, - async () => { + // const { value } = useCachedData( + // 'AaveReservesData', + // BOB_CHAIN_ID, + // async () => { + // if (!uiPoolDataProvider) { + // return []; + // } + + // const currentTimestamp = dayjs().unix(); + // const reservesData = await uiPoolDataProvider.getReservesHumanized({ + // lendingPoolAddressProvider: config.PoolAddressesProviderAddress, + // }); + // const reserves = reservesData.reservesData.filter(r => + // config.assetsWhitelist.includes(r.symbol), + // ); + // const formattedReserves = formatReserves({ + // reserves, + // currentTimestamp, + // marketReferenceCurrencyDecimals: + // reservesData.baseCurrencyData.marketReferenceCurrencyDecimals, + // marketReferencePriceInUsd: + // reservesData.baseCurrencyData.marketReferenceCurrencyPriceInUsd, + // }); + + // return formattedReserves; + // }, + // [uiPoolDataProvider], + // [], + // { ttl: 1000 * 60, fallbackToPreviousResult: true }, + // ); + + const [value, setValue] = useState([]); + useEffect(() => { + const compute = async () => { if (!uiPoolDataProvider) { return []; } @@ -57,11 +89,9 @@ export const useAaveReservesData = (): ReserveData => { }); return formattedReserves; - }, - [uiPoolDataProvider], - [], - { ttl: 1000 * 60, fallbackToPreviousResult: true }, - ); + }; + compute().then(setValue); + }, [uiPoolDataProvider]); return value; }; diff --git a/apps/frontend/src/hooks/aave/useAaveSupply.tsx b/apps/frontend/src/hooks/aave/useAaveSupply.tsx index b6c604114..e2f762323 100644 --- a/apps/frontend/src/hooks/aave/useAaveSupply.tsx +++ b/apps/frontend/src/hooks/aave/useAaveSupply.tsx @@ -58,6 +58,8 @@ export const useAaveSupply = () => { return; } + console.log('asset', asset.address, useAsCollateral); + setTransactions( await aaveSupplyTransactionsFactory.collateralSwitch( asset, diff --git a/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx b/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx index b110be088..4a037a2b2 100644 --- a/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx +++ b/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx @@ -1,22 +1,22 @@ import { UiPoolDataProvider } from '@aave/contract-helpers'; import { formatReserves, formatUserSummary } from '@aave/math-utils'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import dayjs from 'dayjs'; -import { BOB_CHAIN_ID } from '../../config/chains'; - +// import { BOB_CHAIN_ID } from '../../config/chains'; import { config } from '../../constants/aave'; import { AaveUserReservesSummary } from '../../utils/aave/AaveUserReservesSummary'; -import { useCachedData } from '../useCachedData'; +import { useAccount } from '../useAccount'; + +// import { useCachedData } from '../useCachedData'; type UserReservesData = AaveUserReservesSummary | null; export const useAaveUserReservesData = (): UserReservesData => { const provider = config.provider; - const account = '0xF754D0f4de0e815b391D997Eeec5cD07E59858F0'; - // const { account, provider } = useAccount(); TODO: activate this instead of 2 above once calculations in bob are possible + const { account } = useAccount(); const uiPoolDataProvider = useMemo( () => @@ -30,10 +30,53 @@ export const useAaveUserReservesData = (): UserReservesData => { [provider], ); - const { value } = useCachedData( - `AaveUserReservesData/${account}`, - BOB_CHAIN_ID, - async () => { + // const { value } = useCachedData( + // `AaveUserReservesData/${account}`, + // BOB_CHAIN_ID, + // async () => { + // if (!account || !uiPoolDataProvider) { + // return null; + // } + + // const [reservesData, userReservesData] = await Promise.all([ + // uiPoolDataProvider.getReservesHumanized({ + // lendingPoolAddressProvider: config.PoolAddressesProviderAddress, + // }), + // uiPoolDataProvider.getUserReservesHumanized({ + // lendingPoolAddressProvider: config.PoolAddressesProviderAddress, + // user: account, + // }), + // ]); + // const { + // marketReferenceCurrencyDecimals, + // marketReferenceCurrencyPriceInUsd: marketReferencePriceInUsd, + // } = reservesData.baseCurrencyData; + // const currentTimestamp = dayjs().unix(); + + // return AaveUserReservesSummary.from( + // formatUserSummary({ + // currentTimestamp, + // marketReferencePriceInUsd, + // marketReferenceCurrencyDecimals, + // userReserves: userReservesData.userReserves, + // userEmodeCategoryId: userReservesData.userEmodeCategoryId, + // formattedReserves: formatReserves({ + // currentTimestamp, + // marketReferencePriceInUsd, + // marketReferenceCurrencyDecimals, + // reserves: reservesData.reservesData, + // }), + // }), + // ); + // }, + // [uiPoolDataProvider, account], + // null, + // { ttl: 1000 * 60, fallbackToPreviousResult: true }, + // ); + + const [value, setValue] = useState(null); + useEffect(() => { + const compute = async () => { if (!account || !uiPoolDataProvider) { return null; } @@ -68,11 +111,9 @@ export const useAaveUserReservesData = (): UserReservesData => { }), }), ); - }, - [uiPoolDataProvider, account], - null, - { ttl: 1000 * 60, fallbackToPreviousResult: true }, - ); + }; + compute().then(setValue); + }, [uiPoolDataProvider, account]); return value; }; diff --git a/apps/frontend/src/locales/en/translations.json b/apps/frontend/src/locales/en/translations.json index e1297c40d..03a5d083e 100644 --- a/apps/frontend/src/locales/en/translations.json +++ b/apps/frontend/src/locales/en/translations.json @@ -814,7 +814,7 @@ "tx": { "supplyTitle": "Deposit {{symbol}} to the pool", "supplySubtitle": "Transfers {{amount}} {{symbol}} to the pool", - "withdrawTitle": "Withdraw {{asset}} from the pool", + "withdrawTitle": "Withdraw {{symbol}} from the pool", "withdrawSubtitle": "Transfer {{amount}} {{symbol}} from the pool", "repayTitle":"Repay loan", "repaySubtitle": "Repay {{amount}} {{symbol}} to the pool", diff --git a/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts b/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts index c437f1b59..7bf2ae28b 100644 --- a/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts +++ b/apps/frontend/src/utils/aave/AaveRepayTransactionsFactory.ts @@ -1,4 +1,4 @@ -import { BigNumber, constants, ethers } from 'ethers'; +import { BigNumber, constants, Contract, ethers } from 'ethers'; import { t } from 'i18next'; import { AssetDetailsData, getAssetDataByAddress } from '@sovryn/contracts'; @@ -11,6 +11,7 @@ import { } from '../../app/3_organisms/TransactionStepDialog/TransactionStepDialog.types'; import { translations } from '../../locales/i18n'; import { TransactionFactoryOptions } from '../../types/aave'; +import { prepareApproveTransaction } from '../transactions'; import { LoanType } from './AaveUserReservesSummary'; export class AaveRepayTransactionsFactory { @@ -55,30 +56,39 @@ export class AaveRepayTransactionsFactory { loanType: LoanType, opts?: TransactionFactoryOptions, ): Promise { - return [ - { - title: t(translations.aavePage.tx.repayTitle, { - symbol: asset.symbol, - }), - subtitle: t(translations.aavePage.tx.repaySubtitle, { - symbol: asset.symbol, - amount: ethers.utils.formatUnits(amount, asset.decimals), - }), - request: { - type: TransactionType.signTransaction, - args: [ - asset.address, - amount.toString(), - loanType, - await this.signer.getAddress(), - ], - contract: this.Pool, - fnName: 'repay', - value: 0, - }, - onComplete: opts?.onComplete, + const approval = await prepareApproveTransaction({ + spender: this.PoolAddress, + token: asset.symbol, + contract: new Contract(asset.address, asset.abi, this.signer), + amount: amount, + chain: BOB_CHAIN_ID, + }); + const transactions: Transaction[] = approval ? [approval] : []; + + transactions.push({ + title: t(translations.aavePage.tx.repayTitle, { + symbol: asset.symbol, + }), + subtitle: t(translations.aavePage.tx.repaySubtitle, { + symbol: asset.symbol, + amount: ethers.utils.formatUnits(amount, asset.decimals), + }), + request: { + type: TransactionType.signTransaction, + args: [ + asset.address, + amount.toString(), + loanType, + await this.signer.getAddress(), + ], + contract: this.Pool, + fnName: 'repay', + value: 0, }, - ]; + onComplete: opts?.onComplete, + }); + + return transactions; } private async repayNative( diff --git a/apps/frontend/src/utils/aave/AaveSupplyTransactionsFactory.ts b/apps/frontend/src/utils/aave/AaveSupplyTransactionsFactory.ts index fe238f10d..a3e0ea17b 100644 --- a/apps/frontend/src/utils/aave/AaveSupplyTransactionsFactory.ts +++ b/apps/frontend/src/utils/aave/AaveSupplyTransactionsFactory.ts @@ -72,7 +72,7 @@ export class AaveSupplyTransactionsFactory { }), request: { type: TransactionType.signTransaction, - args: [token, useAsCollateral], + args: [token.address, useAsCollateral], contract: this.Pool, fnName: 'setUserUseReserveAsCollateral', }, diff --git a/packages/contracts/src/contracts/assets/bobTestnet.ts b/packages/contracts/src/contracts/assets/bobTestnet.ts index 2fed174eb..8050427bb 100644 --- a/packages/contracts/src/contracts/assets/bobTestnet.ts +++ b/packages/contracts/src/contracts/assets/bobTestnet.ts @@ -42,7 +42,7 @@ export const bobTestnet: Array = [ }, { symbol: 'DAI', - address: '0x2528AC8426DdCbfd2E038D90532F52a9Ad5BD594', + address: '0x4e4e256D3a9789329AB540a7a3b2cd0c03C40431', name: 'DAI Stablecoin', decimals: 18, getIcon: async () => (await import('./icons/bob/dai')).default, @@ -58,7 +58,7 @@ export const bobTestnet: Array = [ symbol: 'USDC', address: '0x509AeFe02953BC2fB8abCa53Fd83C94D86c05922', name: 'USD Coin', - decimals: 6, + decimals: 18, getIcon: async () => (await import('./icons/bob/usdc')).default, }, { @@ -85,9 +85,17 @@ export const bobTestnet: Array = [ { symbol: 'aWETH', // TODO: properly adjust this variable - address: '0xAD51B64c2eeF5877CDF4AcdCC790DF6eaBC6ecbf', + address: '0x1b57354f10EFc441803639F74E9624CcA6Ab7abA', name: 'Aave Wrapped ETH', decimals: 18, getIcon: async () => (await import('./icons/bob/eth')).default, }, + { + symbol: 'WETH', + // TODO: properly adjust this variable + address: '0x936EA1bCF82Fbc1Dbe24c6AA140f136A7De15C2E', + name: 'Wrapped ETH', + decimals: 18, + getIcon: async () => (await import('./icons/bob/eth')).default, + }, ]; From f5de2663c61049eb59f13efdb181afb451f0aff5 Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 19:25:57 +0300 Subject: [PATCH 04/22] refetch user data based on blocknumber --- .../src/hooks/aave/useAaveReservesData.tsx | 55 ++------- .../hooks/aave/useAaveUserReservesData.tsx | 112 ++++++------------ 2 files changed, 49 insertions(+), 118 deletions(-) diff --git a/apps/frontend/src/hooks/aave/useAaveReservesData.tsx b/apps/frontend/src/hooks/aave/useAaveReservesData.tsx index 6105f5e7c..2d135a745 100644 --- a/apps/frontend/src/hooks/aave/useAaveReservesData.tsx +++ b/apps/frontend/src/hooks/aave/useAaveReservesData.tsx @@ -4,15 +4,14 @@ import { } from '@aave/contract-helpers'; import { formatReserves, FormatReserveUSDResponse } from '@aave/math-utils'; -import { useEffect, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import dayjs from 'dayjs'; -import { config } from '../../constants/aave'; +import { BOB_CHAIN_ID } from '../../config/chains'; -// import { BOB_CHAIN_ID } from '../../config/chains'; -// import { useAccount } from '../useAccount'; -// import { useCachedData } from '../useCachedData'; +import { config } from '../../constants/aave'; +import { useCachedData } from '../useCachedData'; export type Reserve = ReserveDataHumanized & FormatReserveUSDResponse; @@ -34,40 +33,10 @@ export const useAaveReservesData = (): ReserveData => { [provider], ); - // const { value } = useCachedData( - // 'AaveReservesData', - // BOB_CHAIN_ID, - // async () => { - // if (!uiPoolDataProvider) { - // return []; - // } - - // const currentTimestamp = dayjs().unix(); - // const reservesData = await uiPoolDataProvider.getReservesHumanized({ - // lendingPoolAddressProvider: config.PoolAddressesProviderAddress, - // }); - // const reserves = reservesData.reservesData.filter(r => - // config.assetsWhitelist.includes(r.symbol), - // ); - // const formattedReserves = formatReserves({ - // reserves, - // currentTimestamp, - // marketReferenceCurrencyDecimals: - // reservesData.baseCurrencyData.marketReferenceCurrencyDecimals, - // marketReferencePriceInUsd: - // reservesData.baseCurrencyData.marketReferenceCurrencyPriceInUsd, - // }); - - // return formattedReserves; - // }, - // [uiPoolDataProvider], - // [], - // { ttl: 1000 * 60, fallbackToPreviousResult: true }, - // ); - - const [value, setValue] = useState([]); - useEffect(() => { - const compute = async () => { + const { value } = useCachedData( + 'AaveReservesData', + BOB_CHAIN_ID, + async () => { if (!uiPoolDataProvider) { return []; } @@ -89,9 +58,11 @@ export const useAaveReservesData = (): ReserveData => { }); return formattedReserves; - }; - compute().then(setValue); - }, [uiPoolDataProvider]); + }, + [uiPoolDataProvider], + [], + { ttl: 1000 * 60, fallbackToPreviousResult: true }, + ); return value; }; diff --git a/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx b/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx index 4a037a2b2..976c29ecf 100644 --- a/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx +++ b/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx @@ -1,22 +1,21 @@ import { UiPoolDataProvider } from '@aave/contract-helpers'; import { formatReserves, formatUserSummary } from '@aave/math-utils'; -import { useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import dayjs from 'dayjs'; -// import { BOB_CHAIN_ID } from '../../config/chains'; import { config } from '../../constants/aave'; import { AaveUserReservesSummary } from '../../utils/aave/AaveUserReservesSummary'; import { useAccount } from '../useAccount'; +import { useBlockNumber } from '../useBlockNumber'; -// import { useCachedData } from '../useCachedData'; - -type UserReservesData = AaveUserReservesSummary | null; - -export const useAaveUserReservesData = (): UserReservesData => { +export const useAaveUserReservesData = (): AaveUserReservesSummary | null => { const provider = config.provider; const { account } = useAccount(); + const [value, setValue] = useState(null); + const { value: blockNumber } = useBlockNumber(); + const [processedBlock, setProcessedBlock] = useState(); const uiPoolDataProvider = useMemo( () => @@ -30,73 +29,28 @@ export const useAaveUserReservesData = (): UserReservesData => { [provider], ); - // const { value } = useCachedData( - // `AaveUserReservesData/${account}`, - // BOB_CHAIN_ID, - // async () => { - // if (!account || !uiPoolDataProvider) { - // return null; - // } - - // const [reservesData, userReservesData] = await Promise.all([ - // uiPoolDataProvider.getReservesHumanized({ - // lendingPoolAddressProvider: config.PoolAddressesProviderAddress, - // }), - // uiPoolDataProvider.getUserReservesHumanized({ - // lendingPoolAddressProvider: config.PoolAddressesProviderAddress, - // user: account, - // }), - // ]); - // const { - // marketReferenceCurrencyDecimals, - // marketReferenceCurrencyPriceInUsd: marketReferencePriceInUsd, - // } = reservesData.baseCurrencyData; - // const currentTimestamp = dayjs().unix(); - - // return AaveUserReservesSummary.from( - // formatUserSummary({ - // currentTimestamp, - // marketReferencePriceInUsd, - // marketReferenceCurrencyDecimals, - // userReserves: userReservesData.userReserves, - // userEmodeCategoryId: userReservesData.userEmodeCategoryId, - // formattedReserves: formatReserves({ - // currentTimestamp, - // marketReferencePriceInUsd, - // marketReferenceCurrencyDecimals, - // reserves: reservesData.reservesData, - // }), - // }), - // ); - // }, - // [uiPoolDataProvider, account], - // null, - // { ttl: 1000 * 60, fallbackToPreviousResult: true }, - // ); - - const [value, setValue] = useState(null); - useEffect(() => { - const compute = async () => { - if (!account || !uiPoolDataProvider) { - return null; - } + const loadUserReservesData = useCallback(async () => { + if (!account || !uiPoolDataProvider) { + return null; + } - const [reservesData, userReservesData] = await Promise.all([ - uiPoolDataProvider.getReservesHumanized({ - lendingPoolAddressProvider: config.PoolAddressesProviderAddress, - }), - uiPoolDataProvider.getUserReservesHumanized({ - lendingPoolAddressProvider: config.PoolAddressesProviderAddress, - user: account, - }), - ]); - const { - marketReferenceCurrencyDecimals, - marketReferenceCurrencyPriceInUsd: marketReferencePriceInUsd, - } = reservesData.baseCurrencyData; - const currentTimestamp = dayjs().unix(); + const [reservesData, userReservesData] = await Promise.all([ + uiPoolDataProvider.getReservesHumanized({ + lendingPoolAddressProvider: config.PoolAddressesProviderAddress, + }), + uiPoolDataProvider.getUserReservesHumanized({ + lendingPoolAddressProvider: config.PoolAddressesProviderAddress, + user: account, + }), + ]); + const { + marketReferenceCurrencyDecimals, + marketReferenceCurrencyPriceInUsd: marketReferencePriceInUsd, + } = reservesData.baseCurrencyData; + const currentTimestamp = dayjs().unix(); - return AaveUserReservesSummary.from( + setValue( + AaveUserReservesSummary.from( formatUserSummary({ currentTimestamp, marketReferencePriceInUsd, @@ -110,10 +64,16 @@ export const useAaveUserReservesData = (): UserReservesData => { reserves: reservesData.reservesData, }), }), - ); - }; - compute().then(setValue); - }, [uiPoolDataProvider, account]); + ), + ); + setProcessedBlock(blockNumber); + }, [account, uiPoolDataProvider, blockNumber]); + + useEffect(() => { + if (blockNumber !== processedBlock) { + loadUserReservesData(); + } + }, [loadUserReservesData, processedBlock, blockNumber]); return value; }; From 2a5aa31134bf94b254bfc13abadf8d2ed02899a1 Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 19:55:49 +0300 Subject: [PATCH 05/22] fix modal closing on lending positions change plus style adjustments --- .../AssetAmountPriceRenderer.tsx | 2 +- .../LendAssetsList.constants.tsx | 15 +++++-- .../LendAssetsList/LendAssetsList.tsx | 41 +++++++++++++++++-- .../components/AssetBalance/AssetBalance.tsx | 6 +-- .../LendAssetAction/LendAssetAction.tsx | 25 ++--------- .../LendAssetDetails/LendAssetDetails.tsx | 10 +++-- .../{LendModal => LendForm}/LendForm.tsx | 0 .../LendModal/LendModalContainer.tsx | 32 --------------- 8 files changed, 62 insertions(+), 69 deletions(-) rename apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/{LendModal => LendForm}/LendForm.tsx (100%) delete mode 100644 apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendModal/LendModalContainer.tsx diff --git a/apps/frontend/src/app/2_molecules/AssetAmountPriceRenderer/AssetAmountPriceRenderer.tsx b/apps/frontend/src/app/2_molecules/AssetAmountPriceRenderer/AssetAmountPriceRenderer.tsx index e77f89d7e..9a8b2dc3c 100644 --- a/apps/frontend/src/app/2_molecules/AssetAmountPriceRenderer/AssetAmountPriceRenderer.tsx +++ b/apps/frontend/src/app/2_molecules/AssetAmountPriceRenderer/AssetAmountPriceRenderer.tsx @@ -24,7 +24,7 @@ export const AssetAmountPriceRenderer: FC = ({ priceClassName, }) => { return ( -
+
unknown) => [ { id: 'asset', sortable: true, @@ -37,20 +37,24 @@ export const COLUMNS_CONFIG = [ { id: 'walletBalance', sortable: true, + className: '[&_*]:mx-auto [&_*]:space-x-2', // center head align: Align.center, title: ( - + {t(pageTranslations.lendAssetsList.walletBalance)} ), cellRenderer: (pool: LendPoolDetails) => ( - +
+ +
), }, { id: 'apy', sortable: true, align: Align.center, + className: '[&_*]:mx-auto [&_*]:space-x-2', // center head title: ( {t(pageTranslations.common.apy)} @@ -65,6 +69,7 @@ export const COLUMNS_CONFIG = [ id: 'canBeCollateral', sortable: true, align: Align.center, + className: '[&_*]:mx-auto [&_*]:space-x-2', // center head title: ( {t(pageTranslations.lendAssetsList.canBeCollateral)} @@ -84,6 +89,8 @@ export const COLUMNS_CONFIG = [ id: 'actions', align: Align.center, title: ' ', - cellRenderer: (pool: LendPoolDetails) => , + cellRenderer: (pool: LendPoolDetails) => ( + onLendClick(pool.asset)} /> + ), }, ]; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx index 45675f242..fe5d12818 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx @@ -2,13 +2,22 @@ import React, { FC, useCallback, useState } from 'react'; import { t } from 'i18next'; -import { Accordion, Checkbox, OrderOptions, Table } from '@sovryn/ui'; +import { + Accordion, + Checkbox, + Dialog, + DialogBody, + DialogHeader, + OrderOptions, + Table, +} from '@sovryn/ui'; import { AaveRowTitle } from '../../../../2_molecules/AavePoolRowTitle/AavePoolRowTitle'; import { translations } from '../../../../../locales/i18n'; import { COLUMNS_CONFIG } from './LendAssetsList.constants'; import { LendPoolDetails } from './LendAssetsList.types'; import { LendAssetDetails } from './components/LendAssetDetails/LendAssetDetails'; +import { LendForm } from './components/LendForm/LendForm'; const pageTranslations = translations.aavePage; @@ -20,8 +29,24 @@ export const LendAssetsList: FC = ({ lendPools }) => { const [open, setOpen] = useState(true); const [showZeroBalances, setShowZeroBalances] = useState(true); const [orderOptions, setOrderOptions] = useState(); + const [lendFormDialog, setLendFormDialog] = useState<{ + asset: string; + open: boolean; + }>({ open: false, asset: '' }); + + const onLendClick = useCallback((asset: string) => { + setLendFormDialog({ asset, open: true }); + }, []); + + const onLendClose = useCallback(() => { + setLendFormDialog({ open: false, asset: '' }); + }, []); + + const mobileRenderer = useCallback( + p => onLendClick(p.asset)} />, + [onLendClick], + ); - const mobileRenderer = useCallback(p => , []); const rowTitleRenderer = useCallback( (r: LendPoolDetails) => ( = ({ lendPools }) => { /> = ({ lendPools }) => { orderOptions={orderOptions} setOrderOptions={setOrderOptions} /> + + + + + + + ); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx index 20bf29341..b52ea6ddf 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/AssetBalance/AssetBalance.tsx @@ -1,4 +1,4 @@ -import React, { FC, useEffect } from 'react'; +import React, { FC } from 'react'; import { BOB_CHAIN_ID } from '../../../../../../../config/chains'; @@ -16,10 +16,6 @@ export const AssetBalanceRenderer: FC = ({ const { account } = useAccount(); const balance = useAssetBalance(asset, BOB_CHAIN_ID); - useEffect(() => { - console.log('account', account, balance); - }, [account, balance]); - return account ? ( unknown; }; -export const LendAssetAction: FC = ({ pool }) => { +export const LendAssetAction: FC = ({ onLendClick }) => { const navigate = useNavigate(); - const [isLendModalOpen, setIsLendModalOpen] = useState(false); - - const handleLendClick = () => { - setIsLendModalOpen(true); - }; - - const handleLendClose = () => { - setIsLendModalOpen(false); - }; return (
); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetDetails/LendAssetDetails.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetDetails/LendAssetDetails.tsx index 7a83ea87b..a51657f4b 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetDetails/LendAssetDetails.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetDetails/LendAssetDetails.tsx @@ -8,14 +8,18 @@ import { HelperButton, Icon, IconNames, SimpleTableRow } from '@sovryn/ui'; import { AmountRenderer } from '../../../../../../2_molecules/AmountRenderer/AmountRenderer'; import { translations } from '../../../../../../../locales/i18n'; import { LendPoolDetails } from '../../LendAssetsList.types'; -import { LendAssetAction } from '../LendAssetAction/LendAssetAction'; import { AssetBalanceRenderer } from '../AssetBalance/AssetBalance'; +import { LendAssetAction } from '../LendAssetAction/LendAssetAction'; type LendAssetDetailsProps = { pool: LendPoolDetails; + onLendClick: () => unknown; }; -export const LendAssetDetails: FC = ({ pool }) => { +export const LendAssetDetails: FC = ({ + pool, + onLendClick, +}) => { return (
@@ -52,7 +56,7 @@ export const LendAssetDetails: FC = ({ pool }) => { />
- +
); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendModal/LendForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx similarity index 100% rename from apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendModal/LendForm.tsx rename to apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendModal/LendModalContainer.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendModal/LendModalContainer.tsx deleted file mode 100644 index 3fe1c2e0c..000000000 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendModal/LendModalContainer.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { FC } from 'react'; - -import { t } from 'i18next'; - -import { Dialog, DialogBody, DialogHeader } from '@sovryn/ui'; - -import { translations } from '../../../../../../../locales/i18n'; -import { LendForm } from './LendForm'; - -type LendModalContainerProps = { - asset: string; - isOpen: boolean; - handleCloseModal: () => unknown; -}; - -export const LendModalContainer: FC = ({ - asset, - isOpen, - handleCloseModal, -}) => { - return ( - - - - - - - ); -}; From 10993b73ff82a7adc58f7f8c0b693c56be14bbb6 Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 20:14:09 +0300 Subject: [PATCH 06/22] fix withdraw modals --- .../LendAssetsList/LendAssetsList.tsx | 13 +++--- .../LendPositionsList.constants.tsx | 6 ++- .../LendPositionsList/LendPositionsList.tsx | 40 ++++++++++++++++--- .../LendPositionAction/LendPositionAction.tsx | 27 ++----------- .../LendPositionDetails.tsx | 6 ++- .../WithdrawForm.tsx | 0 .../WithdrawModal/WithdrawModalContainer.tsx | 32 --------------- 7 files changed, 53 insertions(+), 71 deletions(-) rename apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/{WithdrawModal => WithdrawForm}/WithdrawForm.tsx (100%) delete mode 100644 apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawModalContainer.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx index fe5d12818..dde1d9f8a 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx @@ -29,17 +29,14 @@ export const LendAssetsList: FC = ({ lendPools }) => { const [open, setOpen] = useState(true); const [showZeroBalances, setShowZeroBalances] = useState(true); const [orderOptions, setOrderOptions] = useState(); - const [lendFormDialog, setLendFormDialog] = useState<{ - asset: string; - open: boolean; - }>({ open: false, asset: '' }); + const [lendAssetDialog, setLendAssetDialog] = useState(); const onLendClick = useCallback((asset: string) => { - setLendFormDialog({ asset, open: true }); + setLendAssetDialog(asset); }, []); const onLendClose = useCallback(() => { - setLendFormDialog({ open: false, asset: '' }); + setLendAssetDialog(undefined); }, []); const mobileRenderer = useCallback( @@ -90,13 +87,13 @@ export const LendAssetsList: FC = ({ lendPools }) => { setOrderOptions={setOrderOptions} /> - + - + diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx index 21d40e005..043e1ca69 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx @@ -16,7 +16,7 @@ import { ToggleCollateralAction } from './components/ToggleCollateralAction/Togg const pageTranslations = translations.aavePage; -export const COLUMNS_CONFIG = [ +export const COLUMNS_CONFIG = (onWithdrawClick: (asset: string) => unknown) => [ { id: 'asset', sortable: true, @@ -84,7 +84,9 @@ export const COLUMNS_CONFIG = [ align: Align.center, title: ' ', cellRenderer: (position: LendPosition) => ( - + onWithdrawClick(position.asset)} + /> ), }, ]; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx index 058392cf5..991a353e7 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx @@ -4,6 +4,9 @@ import { t } from 'i18next'; import { Accordion, + Dialog, + DialogBody, + DialogHeader, OrderDirection, OrderOptions, Paragraph, @@ -18,6 +21,7 @@ import { PoolPositionStat } from '../PoolPositionStat/PoolPositionStat'; import { COLUMNS_CONFIG } from './LendPositionsList.constants'; import { LendPosition } from './LendPositionsList.types'; import { LendPositionDetails } from './components/LendPositionDetails/LendPositionDetails'; +import { WithdrawForm } from './components/WithdrawForm/WithdrawForm'; const pageTranslations = translations.aavePage; @@ -36,11 +40,27 @@ export const LendPositionsList: FC = ({ }) => { const { account } = useAccount(); const [open, setOpen] = useState(true); + const [withdrawAssetDialog, setWithdrawAssetDialog] = useState< + string | undefined + >(); const [orderOptions, setOrderOptions] = useState({ orderBy: 'balance', orderDirection: OrderDirection.Asc, }); + const onWithdrawClick = useCallback((asset: string) => { + setWithdrawAssetDialog(asset); + }, []); + + const onWithdrawClose = useCallback(() => { + setWithdrawAssetDialog(undefined); + }, []); + + const mobileRenderer = useCallback( + p => , + [onWithdrawClick], + ); + const rowTitleRenderer = useCallback( (r: LendPosition) => ( = ({ ), [], ); - const mobileRenderer = useCallback( - p => , - [], - ); return ( = ({ precision={2} /> +
= ({ orderOptions={orderOptions} setOrderOptions={setOrderOptions} /> + + + + + + + ) : (
diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionAction/LendPositionAction.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionAction/LendPositionAction.tsx index 4d54d9c65..fe8044f4e 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionAction/LendPositionAction.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionAction/LendPositionAction.tsx @@ -1,44 +1,25 @@ -import React, { FC, useState } from 'react'; +import React, { FC } from 'react'; import { t } from 'i18next'; import { Button, ButtonStyle } from '@sovryn/ui'; import { translations } from '../../../../../../../locales/i18n'; -import { LendPosition } from '../../LendPositionsList.types'; -import { WithdrawModalContainer } from '../WithdrawModal/WithdrawModalContainer'; type LendPositionActionProps = { - position: LendPosition; + onWithdrawClick: () => unknown; }; export const LendPositionAction: FC = ({ - position, + onWithdrawClick, }) => { - const [isWithdrawModalOpen, setIsWithdrawModalOpen] = - useState(false); - - const handleWithdrawClick = () => { - setIsWithdrawModalOpen(true); - }; - - const handleWithdrawClose = () => { - setIsWithdrawModalOpen(false); - }; - return (
); diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionDetails/LendPositionDetails.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionDetails/LendPositionDetails.tsx index 6a076ca75..804578dd6 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionDetails/LendPositionDetails.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/LendPositionDetails/LendPositionDetails.tsx @@ -13,10 +13,12 @@ import { ToggleCollateralAction } from '../ToggleCollateralAction/ToggleCollater type LendPositionDetailsProps = { position: LendPosition; + onWithdrawClick: (asset: string) => void; }; export const LendPositionDetails: FC = ({ position, + onWithdrawClick, }) => { return (
@@ -54,7 +56,9 @@ export const LendPositionDetails: FC = ({ />
- + onWithdrawClick(position.asset)} + />
); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawForm/WithdrawForm.tsx similarity index 100% rename from apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawForm.tsx rename to apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawForm/WithdrawForm.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawModalContainer.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawModalContainer.tsx deleted file mode 100644 index 2e305f622..000000000 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawModal/WithdrawModalContainer.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { FC } from 'react'; - -import { t } from 'i18next'; - -import { Dialog, DialogBody, DialogHeader } from '@sovryn/ui'; - -import { translations } from '../../../../../../../locales/i18n'; -import { WithdrawForm } from './WithdrawForm'; - -type WithdrawModalContainerProps = { - asset: string; - isOpen: boolean; - handleCloseModal: () => unknown; -}; - -export const WithdrawModalContainer: FC = ({ - asset, - isOpen, - handleCloseModal, -}) => { - return ( - - - - - - - ); -}; From 63e657800a3d622cadd6a478da25e188aad0f1c1 Mon Sep 17 00:00:00 2001 From: matzapata Date: Mon, 26 Aug 2024 22:11:26 +0300 Subject: [PATCH 07/22] modal fixes --- .../BorrowAssetsList.constants.tsx | 4 +- .../BorrowAssetsList/BorrowAssetsList.tsx | 44 +++++++++- .../BorrowAssetAction/BorrowAssetAction.tsx | 27 ++---- .../BorrowAssetDetails/BorrowAssetDetails.tsx | 8 +- .../BorrowModal/BorrowModalContainer.tsx | 32 ------- .../BorrowPositionsList.constants.tsx | 4 +- .../BorrowPositionsList.tsx | 44 +++++++++- .../BorrowPositionAction.tsx | 26 +----- .../BorrowPositionDetails.tsx | 4 +- .../components/RepayForm/RepayForm.tsx | 61 ++++++++++++++ .../RepayWithCollateralForm.tsx | 0 .../RepayWithWalletBalanceForm.tsx | 0 .../RepayModal/RepayModalContainer.tsx | 83 ------------------- 13 files changed, 165 insertions(+), 172 deletions(-) delete mode 100644 apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowModalContainer.tsx create mode 100644 apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx rename apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/{RepayModal => RepayForm}/RepayWithCollateralForm.tsx (100%) rename apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/{RepayModal => RepayForm}/RepayWithWalletBalanceForm.tsx (100%) delete mode 100644 apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayModalContainer.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx index 26de062ce..576894b47 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx @@ -15,7 +15,7 @@ import { BorrowAssetAction } from './components/BorrowAssetAction/BorrowAssetAct const pageTranslations = translations.aavePage; -export const COLUMNS_CONFIG = [ +export const COLUMNS_CONFIG = (onBorrowClick: (asset: string) => unknown) => [ { id: 'asset', sortable: true, @@ -79,7 +79,7 @@ export const COLUMNS_CONFIG = [ align: Align.center, title: ' ', cellRenderer: (pool: BorrowPoolDetails) => ( - + onBorrowClick(pool.asset)} /> ), }, ]; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx index 105731d30..2117adf64 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx @@ -2,13 +2,21 @@ import React, { FC, useCallback, useState } from 'react'; import { t } from 'i18next'; -import { Accordion, OrderOptions, Table } from '@sovryn/ui'; +import { + Accordion, + Dialog, + DialogBody, + DialogHeader, + OrderOptions, + Table, +} from '@sovryn/ui'; import { AaveRowTitle } from '../../../../2_molecules/AavePoolRowTitle/AavePoolRowTitle'; import { translations } from '../../../../../locales/i18n'; import { COLUMNS_CONFIG } from './BorrowAssetsList.constants'; import { BorrowPoolDetails } from './BorrowAssetsList.types'; import { BorrowAssetDetails } from './components/BorrowAssetDetails/BorrowAssetDetails'; +import { BorrowForm } from './components/BorrowModal/BorrowForm'; const pageTranslations = translations.aavePage.borrowAssetsList; @@ -21,6 +29,17 @@ export const BorrowAssetsList: FC = ({ }) => { const [open, setOpen] = useState(true); const [orderOptions, setOrderOptions] = useState(); + const [borrowAssetDialog, setBorrowAssetDialog] = useState< + string | undefined + >(); + + const onBorrowClick = useCallback((asset: string) => { + setBorrowAssetDialog(asset); + }, []); + + const onBorrowClose = useCallback(() => { + setBorrowAssetDialog(undefined); + }, []); const rowTitleRenderer = useCallback( (r: BorrowPoolDetails) => ( @@ -34,7 +53,16 @@ export const BorrowAssetsList: FC = ({ ), [], ); - const mobileRenderer = useCallback(p => , []); + + const mobileRenderer = useCallback( + p => ( + onBorrowClick(p.asset)} + pool={p} + /> + ), + [onBorrowClick], + ); return ( = ({ >
= ({ orderOptions={orderOptions} setOrderOptions={setOrderOptions} /> + + + + + + + ); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx index 2ed861934..fd803a5f6 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from 'react'; +import React, { FC } from 'react'; import { t } from 'i18next'; import { useNavigate } from 'react-router-dom'; @@ -6,33 +6,24 @@ import { useNavigate } from 'react-router-dom'; import { Button, ButtonStyle } from '@sovryn/ui'; import { translations } from '../../../../../../../locales/i18n'; -import { BorrowPoolDetails } from '../../BorrowAssetsList.types'; -import { BorrowModalContainer } from '../BorrowModal/BorrowModalContainer'; const pageTranslations = translations.aavePage; type BorrowAssetActionProps = { - pool: BorrowPoolDetails; + onBorrowClick: () => unknown; }; -export const BorrowAssetAction: FC = ({ pool }) => { +export const BorrowAssetAction: FC = ({ + onBorrowClick, +}) => { const navigate = useNavigate(); - const [isBorrowModalOpen, setIsBorrowModalOpen] = useState(false); - - const handleBorrowClick = () => { - setIsBorrowModalOpen(true); - }; - - const handleBorrowClose = () => { - setIsBorrowModalOpen(false); - }; return (
); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx index bb0786511..e6b91f225 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx @@ -14,9 +14,13 @@ const pageTranslations = translations.aavePage; type BorrowAssetDetailsProps = { pool: BorrowPoolDetails; + onBorrowClick: () => void; }; -export const BorrowAssetDetails: FC = ({ pool }) => { +export const BorrowAssetDetails: FC = ({ + pool, + onBorrowClick, +}) => { return (
@@ -48,7 +52,7 @@ export const BorrowAssetDetails: FC = ({ pool }) => { />
- +
); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowModalContainer.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowModalContainer.tsx deleted file mode 100644 index 9a04e0f33..000000000 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowModalContainer.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { FC } from 'react'; - -import { t } from 'i18next'; - -import { Dialog, DialogBody, DialogHeader } from '@sovryn/ui'; - -import { translations } from '../../../../../../../locales/i18n'; -import { BorrowForm } from './BorrowForm'; - -type BorrowModalContainerProps = { - asset: string; - isOpen: boolean; - handleCloseModal: () => unknown; -}; - -export const BorrowModalContainer: FC = ({ - asset, - isOpen, - handleCloseModal, -}) => { - return ( - - - - - - - ); -}; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx index 979f9a652..6b983f0de 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx @@ -15,7 +15,7 @@ import { BorrowPositionAction } from './components/BorrowPositionAction/BorrowPo const pageTranslations = translations.aavePage; -export const COLUMNS_CONFIG = [ +export const COLUMNS_CONFIG = (onRepayClick: (asset: string) => unknown) => [ { id: 'asset', sortable: true, @@ -89,7 +89,7 @@ export const COLUMNS_CONFIG = [ align: Align.center, title: ' ', cellRenderer: (position: BorrowPosition) => ( - + onRepayClick(position.asset)} /> ), }, ]; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx index d96d6d40d..ee9e999a7 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx @@ -2,7 +2,15 @@ import React, { FC, useCallback, useState } from 'react'; import { t } from 'i18next'; -import { Accordion, OrderOptions, Paragraph, Table } from '@sovryn/ui'; +import { + Accordion, + Dialog, + DialogBody, + DialogHeader, + OrderOptions, + Paragraph, + Table, +} from '@sovryn/ui'; import { Decimal } from '@sovryn/utils'; import { AaveRowTitle } from '../../../../2_molecules/AavePoolRowTitle/AavePoolRowTitle'; @@ -13,6 +21,7 @@ import { COLUMNS_CONFIG } from './BorrowPositionsList.constants'; import { BorrowPosition } from './BorrowPositionsList.types'; import { BorrowPositionDetails } from './components/BorrowPositionDetails/BorrowPositionDetails'; import { EfficiencyModeCard } from './components/EfficiencyModeCard/EfficiencyModeCard'; +import { RepayForm } from './components/RepayForm/RepayForm'; const pageTranslations = translations.aavePage; @@ -34,6 +43,17 @@ export const BorrowPositionsList: FC = ({ const { account } = useAccount(); const [open, setOpen] = useState(true); const [orderOptions, setOrderOptions] = useState(); + const [repayAssetDialog, setRepayAssetDialog] = useState< + string | undefined + >(); + + const onRepayClick = useCallback((asset: string) => { + setRepayAssetDialog(asset); + }, []); + + const onRepayClose = useCallback(() => { + setRepayAssetDialog(undefined); + }, []); const rowTitleRenderer = useCallback( (r: BorrowPosition) => ( @@ -48,8 +68,13 @@ export const BorrowPositionsList: FC = ({ ); const mobileRenderer = useCallback( - p => , - [], + p => ( + onRepayClick(p.asset)} + /> + ), + [onRepayClick], ); return ( @@ -94,8 +119,9 @@ export const BorrowPositionsList: FC = ({ precision={2} /> +
= ({ orderOptions={orderOptions} setOrderOptions={setOrderOptions} /> + + + + + + + ) : (
diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionAction/BorrowPositionAction.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionAction/BorrowPositionAction.tsx index 570f58512..eb2b658de 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionAction/BorrowPositionAction.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionAction/BorrowPositionAction.tsx @@ -1,43 +1,25 @@ -import React, { FC, useCallback, useState } from 'react'; +import React, { FC } from 'react'; import { t } from 'i18next'; import { Button, ButtonStyle } from '@sovryn/ui'; import { translations } from '../../../../../../../locales/i18n'; -import { BorrowPosition } from '../../BorrowPositionsList.types'; -import { RepayModalContainer } from '../RepayModal/RepayModalContainer'; type BorrowPositionActionProps = { - position: BorrowPosition; + onRepayClick: () => void; }; export const BorrowPositionAction: FC = ({ - position, + onRepayClick, }) => { - const [isRepayModalOpen, setIsRepayModalOpen] = useState(false); - - const handleRepayClick = useCallback(() => { - setIsRepayModalOpen(true); - }, []); - - const handleRepayClose = useCallback(() => { - setIsRepayModalOpen(false); - }, []); - return (
); diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx index bc95fef97..dadd985f5 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx @@ -13,10 +13,12 @@ import { BorrowPositionAction } from '../BorrowPositionAction/BorrowPositionActi type BorrowPositionDetailsProps = { position: BorrowPosition; + onRepayClick: () => unknown; }; export const BorrowPositionDetails: FC = ({ position, + onRepayClick, }) => { return (
@@ -57,7 +59,7 @@ export const BorrowPositionDetails: FC = ({ />
- +
); }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx new file mode 100644 index 000000000..9b346d3a9 --- /dev/null +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx @@ -0,0 +1,61 @@ +import React, { FC, useState } from 'react'; + +import { t } from 'i18next'; + +import { Paragraph, ParagraphSize, Tabs, TabType } from '@sovryn/ui'; + +import { translations } from '../../../../../../../locales/i18n'; +import { RepayWithCollateralForm } from './RepayWithCollateralForm'; +import { RepayWithWalletBalanceForm } from './RepayWithWalletBalanceForm'; + +type RepayFormProps = { + asset: string; + onSuccess: () => unknown; +}; + +enum RepayWith { + BALANCE = 0, + COLLATERAL, +} + +export const RepayForm: FC = ({ asset, onSuccess }) => { + const [activeTab, setActiveTab] = useState(RepayWith.BALANCE); + + return ( +
+ + {t(translations.aavePage.repayModal.repayWith)} + + + + + {activeTab === RepayWith.BALANCE ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithCollateralForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithCollateralForm.tsx similarity index 100% rename from apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithCollateralForm.tsx rename to apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithCollateralForm.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx similarity index 100% rename from apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayWithWalletBalanceForm.tsx rename to apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayModalContainer.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayModalContainer.tsx deleted file mode 100644 index 9664910b6..000000000 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayModal/RepayModalContainer.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, { FC, useState } from 'react'; - -import { t } from 'i18next'; - -import { - Dialog, - DialogBody, - DialogHeader, - Paragraph, - ParagraphSize, - Tabs, - TabType, -} from '@sovryn/ui'; - -import { translations } from '../../../../../../../locales/i18n'; -import { RepayWithCollateralForm } from './RepayWithCollateralForm'; -import { RepayWithWalletBalanceForm } from './RepayWithWalletBalanceForm'; - -type RepayModalContainerProps = { - asset: string; - isOpen: boolean; - handleCloseModal: () => unknown; -}; - -enum RepayWith { - BALANCE = 0, - COLLATERAL, -} - -export const RepayModalContainer: FC = ({ - asset, - isOpen, - handleCloseModal, -}) => { - const [activeTab, setActiveTab] = useState(RepayWith.BALANCE); - - return ( - - - - - {t(translations.aavePage.repayModal.repayWith)} - - - - - {activeTab === RepayWith.BALANCE ? ( - - ) : ( - - )} - - - ); -}; From 4695ef1acd55b8154bed69e3afcc54d5e3317d89 Mon Sep 17 00:00:00 2001 From: matzapata Date: Tue, 27 Aug 2024 00:19:39 +0300 Subject: [PATCH 08/22] fix calculation add balances and filter zero balances --- .../src/app/5_pages/AavePage/AavePage.tsx | 22 +++++++--- .../components/BorrowModal/BorrowForm.tsx | 22 ++++++---- .../components/RepayForm/RepayForm.tsx | 2 +- .../RepayForm/RepayWithCollateralForm.tsx | 6 ++- .../RepayForm/RepayWithWalletBalanceForm.tsx | 15 ++++--- .../CollateralRatioHealthBar.tsx | 13 ++---- .../CollateralRatioHealthBar.utils.tsx | 7 ++- .../LendAssetsList.constants.tsx | 5 +-- .../LendAssetsList/LendAssetsList.tsx | 11 ++++- .../LendAssetsList/LendAssetsList.types.tsx | 1 + apps/frontend/src/constants/aave.ts | 5 +-- .../hooks/aave/useAaveUserReservesData.tsx | 43 +++++++++++++++++-- .../src/utils/aave/AaveUserReservesSummary.ts | 21 +++++++-- 13 files changed, 122 insertions(+), 51 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx index 7957ccd2d..b8bd4b85f 100644 --- a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx @@ -70,15 +70,25 @@ const AavePage: FC = () => { } }, [reserves, userReservesSummary]); - const lendPools: LendPoolDetails[] = useMemo( - () => - reserves.map(r => ({ + const lendPools: LendPoolDetails[] = useMemo(() => { + if (!userReservesSummary) { + return reserves.map(r => ({ asset: r.symbol, apy: Decimal.from(r.supplyAPY).mul(100), canBeCollateral: r.usageAsCollateralEnabled, - })), - [reserves], - ); + walletBalance: Decimal.from(0), + })); + } else { + return reserves.map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.supplyAPY).mul(100), + canBeCollateral: r.usageAsCollateralEnabled, + walletBalance: + userReservesSummary.balances.find(b => b.asset.symbol === r.symbol) + ?.balanceDecimal || Decimal.from(0), + })); + } + }, [reserves, userReservesSummary]); return (
diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx index b1cf7b5af..9fd8badf3 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx @@ -52,19 +52,20 @@ export const BorrowForm: FC = ({ asset }) => { return Decimal.from(reserve.variableBorrowAPR).mul(100); }, [reserve]); + const borrowUsdAmount = useMemo(() => { + return borrowSize.mul(reserve?.priceInUSD ?? 0); + }, [borrowSize, reserve]); + const maximumBorrowAmount = useMemo(() => { if (!reserve || !userReservesSummary) return Decimal.from(0); - // deducted from hf=kte/borrowed => newhf=kte/borrowed+new_borrow => MinHealthFactor = newhf - return userReservesSummary.borrowBalance.mul( - userReservesSummary.healthFactor.div(config.MinHealthFactor).sub(1), - ); + // deducted from minCr = coll / (borrowed + maxBorrowed) + return userReservesSummary.collateralBalance + .div(config.MinCollateralRatio) + .sub(userReservesSummary.borrowBalance) + .div(reserve.priceInUSD); }, [userReservesSummary, reserve]); - const borrowUsdAmount = useMemo(() => { - return borrowSize.mul(reserve?.priceInUSD ?? 0); - }, [borrowSize, reserve]); - const borrowableAssetsOptions = useMemo( () => reserves.map(r => ({ @@ -148,7 +149,10 @@ export const BorrowForm: FC = ({ asset }) => { /> - + = ({ asset, onSuccess }) => { const [activeTab, setActiveTab] = useState(RepayWith.BALANCE); return ( -
+
= () => { )}
- + { @@ -109,10 +110,9 @@ export const RepayWithWalletBalanceForm: FC< if (!userReservesSummary) return Decimal.from(0); if (newDebtAmountUSD.eq(0)) return Decimal.from('100000000'); - const newHealthFactor = userReservesSummary.healthFactor - .mul(userReservesSummary.borrowBalance) - .div(newDebtAmountUSD); - return newHealthFactor.div(userReservesSummary.currentLiquidationThreshold); + return userReservesSummary.collateralBalance.div( + userReservesSummary.borrowBalance.add(newDebtAmountUSD), + ); }, [userReservesSummary, newDebtAmountUSD]); const isValidRepayAmount = useMemo( @@ -144,7 +144,10 @@ export const RepayWithWalletBalanceForm: FC< )}
- + = ({ ratio, - thresholds, + minimum, }) => { const collateralRatioThresholds = useMemo( - () => thresholds ?? getCollateralRatioThresholds(), - [thresholds], + () => getCollateralRatioThresholds(minimum), + [minimum], ); return ( diff --git a/apps/frontend/src/app/5_pages/AavePage/components/CollateralRatioHealthBar/CollateralRatioHealthBar.utils.tsx b/apps/frontend/src/app/5_pages/AavePage/components/CollateralRatioHealthBar/CollateralRatioHealthBar.utils.tsx index fb0b10ad4..a70156331 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/CollateralRatioHealthBar/CollateralRatioHealthBar.utils.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/CollateralRatioHealthBar/CollateralRatioHealthBar.utils.tsx @@ -1,8 +1,7 @@ -import { MINIMUM_COLLATERAL_RATIO_LENDING_POOLS } from '../../../../../constants/lending'; +import { Decimal } from '@sovryn/utils'; -export const getCollateralRatioThresholds = () => { - const minimumCollateralRatio = - MINIMUM_COLLATERAL_RATIO_LENDING_POOLS.mul(100); +export const getCollateralRatioThresholds = (minimum: Decimal) => { + const minimumCollateralRatio = minimum.mul(100); return { START: minimumCollateralRatio.mul(0.9).toNumber(), diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.constants.tsx index b885e860f..d46c2358d 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.constants.tsx @@ -10,7 +10,6 @@ import { AmountRenderer } from '../../../../2_molecules/AmountRenderer/AmountRen import { AssetRenderer } from '../../../../2_molecules/AssetRenderer/AssetRenderer'; import { translations } from '../../../../../locales/i18n'; import { LendPoolDetails } from './LendAssetsList.types'; -import { AssetBalanceRenderer } from './components/AssetBalance/AssetBalance'; import { LendAssetAction } from './components/LendAssetAction/LendAssetAction'; const pageTranslations = translations.aavePage; @@ -45,9 +44,7 @@ export const COLUMNS_CONFIG = (onLendClick: (asset: string) => unknown) => [ ), cellRenderer: (pool: LendPoolDetails) => ( -
- -
+ ), }, { diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx index dde1d9f8a..2fc555ad9 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx @@ -1,4 +1,4 @@ -import React, { FC, useCallback, useState } from 'react'; +import React, { FC, useCallback, useMemo, useState } from 'react'; import { t } from 'i18next'; @@ -57,6 +57,13 @@ export const LendAssetsList: FC = ({ lendPools }) => { [], ); + const filteredLendPools = useMemo(() => { + if (!showZeroBalances) { + return lendPools.filter(p => p.walletBalance.gt(0)); + } + return lendPools; + }, [lendPools, showZeroBalances]); + return ( = ({ lendPools }) => { accordionClassName="bg-gray-60 border border-gray-70" rowTitle={rowTitleRenderer} mobileRenderer={mobileRenderer} - rows={lendPools} + rows={filteredLendPools} orderOptions={orderOptions} setOrderOptions={setOrderOptions} /> diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.types.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.types.tsx index d5232ddf5..49bd834ec 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.types.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.types.tsx @@ -4,4 +4,5 @@ export type LendPoolDetails = { asset: string; apy: Decimal; canBeCollateral: boolean; + walletBalance: Decimal; }; diff --git a/apps/frontend/src/constants/aave.ts b/apps/frontend/src/constants/aave.ts index 2041b4cc5..c1cb215bd 100644 --- a/apps/frontend/src/constants/aave.ts +++ b/apps/frontend/src/constants/aave.ts @@ -1,10 +1,10 @@ import { ethers } from 'ethers'; -import { Decimal } from '@sovryn/utils'; +import { decimalic } from '../utils/math'; export const config = { chainId: 111, - MinHealthFactor: Decimal.from('1.05'), + MinCollateralRatio: decimalic(1.5), PoolAddress: '0xD0Fb3Eb747A368f01d1598faF1F1C55a33416429', WETHGatewayAddress: '0x5723D6ABA3e46375C343A82fEC9e05a465dE387B', VariableDebtWETHAddress: '0x1F016249e1bCa541f4BFb1268aF3f4f293eAf082', @@ -13,7 +13,6 @@ export const config = { assetsWhitelist: ['DAI', 'USDC', 'USDT', 'BTC', 'WETH', 'EURS'], provider: new ethers.providers.JsonRpcProvider( - // 'https://polygon-bor-rpc.publicnode.com', 'https://testnet.rpc.gobob.xyz', ), }; diff --git a/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx b/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx index 976c29ecf..d74535498 100644 --- a/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx +++ b/apps/frontend/src/hooks/aave/useAaveUserReservesData.tsx @@ -4,9 +4,19 @@ import { formatReserves, formatUserSummary } from '@aave/math-utils'; import { useCallback, useEffect, useMemo, useState } from 'react'; import dayjs from 'dayjs'; +import { BigNumber } from 'ethers'; + +import { getAssetData } from '@sovryn/contracts'; +import { Decimal } from '@sovryn/utils'; + +import { BOB_CHAIN_ID } from '../../config/chains'; import { config } from '../../constants/aave'; -import { AaveUserReservesSummary } from '../../utils/aave/AaveUserReservesSummary'; +import { + AaveUserReservesSummary, + AssetBalance, +} from '../../utils/aave/AaveUserReservesSummary'; +import { decimalic, fromWei } from '../../utils/math'; import { useAccount } from '../useAccount'; import { useBlockNumber } from '../useBlockNumber'; @@ -30,7 +40,7 @@ export const useAaveUserReservesData = (): AaveUserReservesSummary | null => { ); const loadUserReservesData = useCallback(async () => { - if (!account || !uiPoolDataProvider) { + if (!account || !uiPoolDataProvider || !provider || !blockNumber) { return null; } @@ -49,6 +59,32 @@ export const useAaveUserReservesData = (): AaveUserReservesSummary | null => { } = reservesData.baseCurrencyData; const currentTimestamp = dayjs().unix(); + const balances: AssetBalance[] = await Promise.all( + reservesData.reservesData.map(async r => { + const asset = await getAssetData(r.symbol, BOB_CHAIN_ID); + + try { + const balance = asset.isNative + ? await provider.getBalance(account) + : await asset.contract(provider).balanceOf(account); + + return { + asset, + balance: BigNumber.from(balance), + balanceDecimal: decimalic( + fromWei(balance.toString(), asset.decimals), + ), + }; + } catch (e) { + return { + asset, + balance: BigNumber.from(0), + balanceDecimal: Decimal.ZERO, + }; + } + }), + ); + setValue( AaveUserReservesSummary.from( formatUserSummary({ @@ -64,10 +100,11 @@ export const useAaveUserReservesData = (): AaveUserReservesSummary | null => { reserves: reservesData.reservesData, }), }), + balances, ), ); setProcessedBlock(blockNumber); - }, [account, uiPoolDataProvider, blockNumber]); + }, [account, uiPoolDataProvider, blockNumber, provider]); useEffect(() => { if (blockNumber !== processedBlock) { diff --git a/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts b/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts index 0e31f6509..53f653578 100644 --- a/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts +++ b/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts @@ -4,12 +4,21 @@ import { FormatUserSummaryResponse, } from '@aave/math-utils'; +import { BigNumber } from 'ethers'; + +import { AssetDetailsData } from '@sovryn/contracts'; import { Decimal } from '@sovryn/utils'; -type UserSummary = FormatUserSummaryResponse< +export type UserSummary = FormatUserSummaryResponse< ReserveDataHumanized & FormatReserveUSDResponse >; +export type AssetBalance = { + asset: AssetDetailsData; + balance: BigNumber; + balanceDecimal: Decimal; +}; + export enum LoanType { STABLE = 1, VARIABLE = 2, @@ -47,10 +56,15 @@ export class AaveUserReservesSummary { public borrowPowerUsed: Decimal; public suppliedAssets: SuppliedAsset[]; public borrowedAssets: BorrowedAsset[]; + public balances: AssetBalance[]; public eModeEnabled: boolean; - constructor(private readonly userSummary: UserSummary) { + constructor( + private readonly userSummary: UserSummary, + balances: AssetBalance[], + ) { // balances + this.balances = balances; this.netWorth = Decimal.from(this.userSummary.netWorthUSD); this.borrowBalance = Decimal.from(this.userSummary.totalBorrowsUSD); this.supplyBalance = this.computeSuppliedBalance( @@ -109,8 +123,9 @@ export class AaveUserReservesSummary { userSummary: FormatUserSummaryResponse< ReserveDataHumanized & FormatReserveUSDResponse >, + balances: AssetBalance[], ) { - return new AaveUserReservesSummary(userSummary); + return new AaveUserReservesSummary(userSummary, balances); } private computeNetApy( From 86e0b083d451277019514f937bc9bde1130f7e9d Mon Sep 17 00:00:00 2001 From: matzapata Date: Tue, 27 Aug 2024 17:39:43 +0300 Subject: [PATCH 09/22] use memo items --- .../components/RepayForm/RepayForm.tsx | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx index 7a8547c42..52896d915 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from 'react'; +import React, { FC, useMemo, useState } from 'react'; import { t } from 'i18next'; @@ -21,6 +21,22 @@ enum RepayWith { export const RepayForm: FC = ({ asset, onSuccess }) => { const [activeTab, setActiveTab] = useState(RepayWith.BALANCE); + const items = useMemo(() => { + return [ + { + activeClassName: 'text-primary-20', + dataAttribute: 'wallet-balance', + label: t(translations.aavePage.repayModal.walletBalance), + }, + { + activeClassName: 'text-primary-20', + dataAttribute: 'collateral', + label: t(translations.aavePage.common.collateral), + disabled: true, + }, + ]; + }, []); + return (
= ({ asset, onSuccess }) => { contentClassName="p-4" index={activeTab} onChange={setActiveTab} - items={[ - { - activeClassName: 'text-primary-20', - dataAttribute: 'wallet-balance', - label: t(translations.aavePage.repayModal.walletBalance), - }, - { - activeClassName: 'text-primary-20', - dataAttribute: 'collateral', - label: t(translations.aavePage.common.collateral), - disabled: true, - }, - ]} + items={items} type={TabType.secondary} /> From b1561cf7aa8480a6d450fd5fb5400d7e3098bb96 Mon Sep 17 00:00:00 2001 From: matzapata Date: Tue, 27 Aug 2024 18:00:14 +0300 Subject: [PATCH 10/22] fix dependencies --- .../components/BorrowModal/BorrowForm.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx index 9fd8badf3..cebd0620b 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx @@ -54,17 +54,26 @@ export const BorrowForm: FC = ({ asset }) => { const borrowUsdAmount = useMemo(() => { return borrowSize.mul(reserve?.priceInUSD ?? 0); - }, [borrowSize, reserve]); + }, [borrowSize, reserve?.priceInUSD]); const maximumBorrowAmount = useMemo(() => { - if (!reserve || !userReservesSummary) return Decimal.from(0); + if ( + !reserve?.priceInUSD || + !userReservesSummary?.collateralBalance || + !userReservesSummary?.borrowBalance + ) + return Decimal.from(0); // deducted from minCr = coll / (borrowed + maxBorrowed) return userReservesSummary.collateralBalance .div(config.MinCollateralRatio) .sub(userReservesSummary.borrowBalance) .div(reserve.priceInUSD); - }, [userReservesSummary, reserve]); + }, [ + reserve?.priceInUSD, + userReservesSummary?.collateralBalance, + userReservesSummary?.borrowBalance, + ]); const borrowableAssetsOptions = useMemo( () => From 391223216ee7ddeb81d3f3fce0aaf9995c58387a Mon Sep 17 00:00:00 2001 From: matzapata Date: Tue, 27 Aug 2024 19:08:00 +0300 Subject: [PATCH 11/22] data normalizers --- .../src/app/5_pages/AavePage/AavePage.tsx | 109 +++++++----------- .../app/5_pages/AavePage/AavePage.utils.tsx | 80 +++++++++++++ 2 files changed, 119 insertions(+), 70 deletions(-) create mode 100644 apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx index b8bd4b85f..374e7b277 100644 --- a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx @@ -5,11 +5,16 @@ import { t } from 'i18next'; import { Helmet } from 'react-helmet-async'; import { Tabs, TabSize, TabType } from '@sovryn/ui'; -import { Decimal } from '@sovryn/utils'; import { useAaveReservesData } from '../../../hooks/aave/useAaveReservesData'; import { useAaveUserReservesData } from '../../../hooks/aave/useAaveUserReservesData'; import { translations } from '../../../locales/i18n'; +import { + normalizeBorrowPoolDetails, + normalizeBorrowPositions, + normalizeLendPoolDetails, + normalizeLendPositions, +} from './AavePage.utils'; import { BorrowAssetsList } from './components/BorrowAssetsList/BorrowAssetsList'; import { BorrowPoolDetails } from './components/BorrowAssetsList/BorrowAssetsList.types'; import { BorrowPositionsList } from './components/BorrowPositionsList/BorrowPositionsList'; @@ -32,63 +37,37 @@ const AavePage: FC = () => { const userReservesSummary = useAaveUserReservesData(); const [activeTab, setActiveTab] = useState(ActiveTab.LEND); - const lendPositions: LendPosition[] = useMemo(() => { - if (!userReservesSummary) return []; - return userReservesSummary.suppliedAssets.map(s => ({ - asset: s.asset, - apy: s.apy, - supplied: s.supplied, - suppliedUSD: s.suppliedUSD, - collateral: s.isCollateral, - })); - }, [userReservesSummary]); - - const borrowPositions: BorrowPosition[] = useMemo(() => { - if (!userReservesSummary) return []; - return userReservesSummary.borrowedAssets.map(ba => ({ - asset: ba.asset, - apy: ba.apy, - borrowed: ba.borrowed, - borrowedUSD: ba.borrowedUSD, - type: ba.type, - })); - }, [userReservesSummary]); - - const borrowPools: BorrowPoolDetails[] = useMemo(() => { - if (!userReservesSummary) { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.variableBorrowAPY).mul(100), - })); - } else { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.variableBorrowAPY).mul(100), - available: userReservesSummary.borrowPower.div(r.priceInUSD), - availableUSD: userReservesSummary.borrowPower, - })); - } - }, [reserves, userReservesSummary]); - - const lendPools: LendPoolDetails[] = useMemo(() => { - if (!userReservesSummary) { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.supplyAPY).mul(100), - canBeCollateral: r.usageAsCollateralEnabled, - walletBalance: Decimal.from(0), - })); - } else { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.supplyAPY).mul(100), - canBeCollateral: r.usageAsCollateralEnabled, - walletBalance: - userReservesSummary.balances.find(b => b.asset.symbol === r.symbol) - ?.balanceDecimal || Decimal.from(0), - })); - } - }, [reserves, userReservesSummary]); + const lendPositions: LendPosition[] = + normalizeLendPositions(userReservesSummary); + + const borrowPositions: BorrowPosition[] = + normalizeBorrowPositions(userReservesSummary); + + const borrowPools: BorrowPoolDetails[] = normalizeBorrowPoolDetails( + reserves, + userReservesSummary, + ); + + const lendPools: LendPoolDetails[] = normalizeLendPoolDetails( + reserves, + userReservesSummary, + ); + + const items = useMemo( + () => [ + { + activeClassName: 'text-primary-20', + dataAttribute: 'lending', + label: t(pageTranslations.common.lend), + }, + { + activeClassName: 'text-primary-20', + dataAttribute: 'borrowing', + label: t(pageTranslations.common.borrow), + }, + ], + [], + ); return (
@@ -107,18 +86,7 @@ const AavePage: FC = () => { setActiveTab(e)} size={TabSize.normal} type={TabType.secondary} @@ -162,4 +130,5 @@ const AavePage: FC = () => {
); }; + export default AavePage; diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx new file mode 100644 index 000000000..6e16d4417 --- /dev/null +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx @@ -0,0 +1,80 @@ +import { Decimal } from '@sovryn/utils'; + +import { ReserveData } from '../../../hooks/aave/useAaveReservesData'; +import { AaveUserReservesSummary } from '../../../utils/aave/AaveUserReservesSummary'; +import { BorrowPosition } from './components/BorrowPositionsList/BorrowPositionsList.types'; +import { LendPosition } from './components/LendPositionsList/LendPositionsList.types'; + +export function normalizeLendPositions( + userReservesSummary: AaveUserReservesSummary | null, +): LendPosition[] { + if (!userReservesSummary) { + return []; + } + + return userReservesSummary.suppliedAssets.map(s => ({ + asset: s.asset, + apy: s.apy, + supplied: s.supplied, + suppliedUSD: s.suppliedUSD, + collateral: s.isCollateral, + })); +} + +export function normalizeBorrowPositions( + userReservesSummary: AaveUserReservesSummary | null, +): BorrowPosition[] { + if (!userReservesSummary) { + return []; + } + + return userReservesSummary.borrowedAssets.map(ba => ({ + asset: ba.asset, + apy: ba.apy, + borrowed: ba.borrowed, + borrowedUSD: ba.borrowedUSD, + type: ba.type, + })); +} + +export function normalizeBorrowPoolDetails( + reserves: ReserveData, + userReservesSummary: AaveUserReservesSummary | null, +) { + if (!userReservesSummary) { + return reserves.map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.variableBorrowAPY).mul(100), + })); + } else { + return reserves.map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.variableBorrowAPY).mul(100), + available: userReservesSummary.borrowPower.div(r.priceInUSD), + availableUSD: userReservesSummary.borrowPower, + })); + } +} + +export function normalizeLendPoolDetails( + reserves: ReserveData, + userReservesSummary: AaveUserReservesSummary | null, +) { + if (!userReservesSummary) { + return reserves.map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.supplyAPY).mul(100), + canBeCollateral: r.usageAsCollateralEnabled, + walletBalance: Decimal.from(0), + })); + } else { + return reserves.map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.supplyAPY).mul(100), + canBeCollateral: r.usageAsCollateralEnabled, + walletBalance: + userReservesSummary.balances.find(b => b.asset.symbol === r.symbol) + ?.balanceDecimal || Decimal.from(0), + })); + } +} From a352bbbf0c05187ad3aac8fd9743bc97aa04b738 Mon Sep 17 00:00:00 2001 From: Matias Zapata <42716817+matzapata@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:16:08 -0300 Subject: [PATCH 12/22] Apply suggestions from code review Co-authored-by: Juan --- .../components/BorrowAssetsList/BorrowAssetsList.constants.tsx | 2 +- .../components/BorrowAssetAction/BorrowAssetAction.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx index 576894b47..48630e3cc 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx @@ -15,7 +15,7 @@ import { BorrowAssetAction } from './components/BorrowAssetAction/BorrowAssetAct const pageTranslations = translations.aavePage; -export const COLUMNS_CONFIG = (onBorrowClick: (asset: string) => unknown) => [ +export const COLUMNS_CONFIG = (onBorrowClick: (asset: string) => void) => [ { id: 'asset', sortable: true, diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx index fd803a5f6..94444fded 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetAction/BorrowAssetAction.tsx @@ -10,7 +10,7 @@ import { translations } from '../../../../../../../locales/i18n'; const pageTranslations = translations.aavePage; type BorrowAssetActionProps = { - onBorrowClick: () => unknown; + onBorrowClick: () => void; }; export const BorrowAssetAction: FC = ({ From 42411cb62942db60696740b5f38854d6012e323f Mon Sep 17 00:00:00 2001 From: Matias Zapata <42716817+matzapata@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:19:24 -0300 Subject: [PATCH 13/22] Update apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetAction/LendAssetAction.tsx Co-authored-by: Juan --- .../components/LendAssetAction/LendAssetAction.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetAction/LendAssetAction.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetAction/LendAssetAction.tsx index f8caea95e..fd9669155 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetAction/LendAssetAction.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendAssetAction/LendAssetAction.tsx @@ -8,7 +8,7 @@ import { Button, ButtonStyle } from '@sovryn/ui'; import { translations } from '../../../../../../../locales/i18n'; type LendAssetActionProps = { - onLendClick: () => unknown; + onLendClick: () => void; }; export const LendAssetAction: FC = ({ onLendClick }) => { From cf37c0505dee4582f176da9b9509c595d96b6d39 Mon Sep 17 00:00:00 2001 From: Matias Zapata <42716817+matzapata@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:23:08 -0300 Subject: [PATCH 14/22] Update apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx Co-authored-by: Juan --- .../LendPositionsList/LendPositionsList.constants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx index 043e1ca69..efe600bff 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.constants.tsx @@ -16,7 +16,7 @@ import { ToggleCollateralAction } from './components/ToggleCollateralAction/Togg const pageTranslations = translations.aavePage; -export const COLUMNS_CONFIG = (onWithdrawClick: (asset: string) => unknown) => [ +export const COLUMNS_CONFIG = (onWithdrawClick: (asset: string) => void) => [ { id: 'asset', sortable: true, From e47f96e7cd55df2acf4eb74c9adc35d05d69658f Mon Sep 17 00:00:00 2001 From: matzapata Date: Wed, 28 Aug 2024 17:07:14 +0300 Subject: [PATCH 15/22] wip refactor done. Missing hooks merge --- .../src/app/5_pages/AavePage/AavePage.tsx | 18 +- .../app/5_pages/AavePage/AavePage.utils.tsx | 91 +++-- .../components/BorrowModal/BorrowForm.tsx | 127 +++--- .../RepayForm/RepayWithWalletBalanceForm.tsx | 93 ++--- .../components/WithdrawForm/WithdrawForm.tsx | 75 ++-- .../hooks/aave/useAaveUserReservesData.tsx | 76 +--- .../src/utils/aave/AaveCalculations.ts | 123 ++++++ .../src/utils/aave/AaveUserReservesSummary.ts | 377 ++++++++---------- 8 files changed, 511 insertions(+), 469 deletions(-) create mode 100644 apps/frontend/src/utils/aave/AaveCalculations.ts diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx index 374e7b277..a0d2da114 100644 --- a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx @@ -37,15 +37,19 @@ const AavePage: FC = () => { const userReservesSummary = useAaveUserReservesData(); const [activeTab, setActiveTab] = useState(ActiveTab.LEND); - const lendPositions: LendPosition[] = - normalizeLendPositions(userReservesSummary); + const lendPositions: LendPosition[] = useMemo( + () => normalizeLendPositions(userReservesSummary), + [userReservesSummary], + ); - const borrowPositions: BorrowPosition[] = - normalizeBorrowPositions(userReservesSummary); + const borrowPositions: BorrowPosition[] = useMemo( + () => normalizeBorrowPositions(userReservesSummary), + [userReservesSummary], + ); - const borrowPools: BorrowPoolDetails[] = normalizeBorrowPoolDetails( - reserves, - userReservesSummary, + const borrowPools: BorrowPoolDetails[] = useMemo( + () => normalizeBorrowPoolDetails(reserves, userReservesSummary), + [reserves, userReservesSummary], ); const lendPools: LendPoolDetails[] = normalizeLendPoolDetails( diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx index 6e16d4417..b81129f88 100644 --- a/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx @@ -1,58 +1,65 @@ import { Decimal } from '@sovryn/utils'; import { ReserveData } from '../../../hooks/aave/useAaveReservesData'; -import { AaveUserReservesSummary } from '../../../utils/aave/AaveUserReservesSummary'; +import { + AaveUserReservesSummary, + LoanType, +} from '../../../utils/aave/AaveUserReservesSummary'; import { BorrowPosition } from './components/BorrowPositionsList/BorrowPositionsList.types'; import { LendPosition } from './components/LendPositionsList/LendPositionsList.types'; export function normalizeLendPositions( - userReservesSummary: AaveUserReservesSummary | null, + userReservesSummary: AaveUserReservesSummary, ): LendPosition[] { - if (!userReservesSummary) { - return []; - } - - return userReservesSummary.suppliedAssets.map(s => ({ - asset: s.asset, - apy: s.apy, - supplied: s.supplied, - suppliedUSD: s.suppliedUSD, - collateral: s.isCollateral, - })); + return userReservesSummary.reserves + .filter(r => r.supplied.gt(0)) + .map(s => ({ + asset: s.reserve.symbol, + apy: Decimal.from(s.reserve.variableBorrowAPY), + supplied: s.supplied, + suppliedUSD: s.suppliedUSD, + collateral: s.collateral, + })); } export function normalizeBorrowPositions( - userReservesSummary: AaveUserReservesSummary | null, + userReservesSummary: AaveUserReservesSummary, ): BorrowPosition[] { - if (!userReservesSummary) { - return []; - } - - return userReservesSummary.borrowedAssets.map(ba => ({ - asset: ba.asset, - apy: ba.apy, - borrowed: ba.borrowed, - borrowedUSD: ba.borrowedUSD, - type: ba.type, - })); + return userReservesSummary.reserves + .filter(r => r.borrowed.gt(0)) + .map(r => ({ + asset: r.reserve.symbol, + apy: Decimal.from( + r.borrowMode === LoanType.STABLE + ? Decimal.from(r.reserve.stableBorrowAPY).mul(100) + : Decimal.from(r.reserve.variableBorrowAPY).mul(100), + ), + borrowed: r.borrowed, + borrowedUSD: r.borrowedUSD, + type: r.borrowMode, + })); } export function normalizeBorrowPoolDetails( reserves: ReserveData, - userReservesSummary: AaveUserReservesSummary | null, + userReservesSummary: AaveUserReservesSummary, ) { if (!userReservesSummary) { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.variableBorrowAPY).mul(100), - })); + return reserves + .filter(r => r.borrowingEnabled) + .map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.variableBorrowAPY).mul(100), + })); } else { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.variableBorrowAPY).mul(100), - available: userReservesSummary.borrowPower.div(r.priceInUSD), - availableUSD: userReservesSummary.borrowPower, - })); + return reserves + .filter(r => r.borrowingEnabled) + .map(r => ({ + asset: r.symbol, + apy: Decimal.from(r.variableBorrowAPY).mul(100), + available: userReservesSummary.borrowPower.div(r.priceInUSD), + availableUSD: userReservesSummary.borrowPower, + })); } } @@ -68,13 +75,11 @@ export function normalizeLendPoolDetails( walletBalance: Decimal.from(0), })); } else { - return reserves.map(r => ({ - asset: r.symbol, - apy: Decimal.from(r.supplyAPY).mul(100), - canBeCollateral: r.usageAsCollateralEnabled, - walletBalance: - userReservesSummary.balances.find(b => b.asset.symbol === r.symbol) - ?.balanceDecimal || Decimal.from(0), + return userReservesSummary.reserves.map(r => ({ + asset: r.reserve.symbol, + apy: Decimal.from(r.reserve.supplyAPY).mul(100), + canBeCollateral: r.reserve.usageAsCollateralEnabled, + walletBalance: r.walletBalance, })); } } diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx index cebd0620b..a64e65b1b 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx @@ -21,12 +21,12 @@ import { AssetAmountInput } from '../../../../../../2_molecules/AssetAmountInput import { AssetRenderer } from '../../../../../../2_molecules/AssetRenderer/AssetRenderer'; import { config } from '../../../../../../../constants/aave'; import { useAaveBorrow } from '../../../../../../../hooks/aave/useAaveBorrow'; -import { useAaveReservesData } from '../../../../../../../hooks/aave/useAaveReservesData'; import { useAaveUserReservesData } from '../../../../../../../hooks/aave/useAaveUserReservesData'; import { useDecimalAmountInput } from '../../../../../../../hooks/useDecimalAmountInput'; import { translations } from '../../../../../../../locales/i18n'; import { BorrowRateMode } from '../../../../../../../types/aave'; import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; +import { AaveCalculations } from '../../../../../../../utils/aave/AaveCalculations'; const pageTranslations = translations.aavePage; @@ -36,90 +36,72 @@ type BorrowFormProps = { }; export const BorrowForm: FC = ({ asset }) => { - const reserves = useAaveReservesData(); const userReservesSummary = useAaveUserReservesData(); const [borrowAsset, setBorrowAsset] = useState(asset); const [borrowAmount, setBorrowAmount, borrowSize] = useDecimalAmountInput(''); const [acknowledge, setAcknowledge] = useState(false); const { handleBorrow } = useAaveBorrow(); - const reserve = useMemo(() => { - return reserves.find(r => r.symbol === borrowAsset); - }, [reserves, borrowAsset]); + const borrowableAssetsOptions = useMemo( + () => + userReservesSummary.reserves + .filter(r => r.reserve.borrowingEnabled) + .map(r => ({ + value: r.reserve.symbol, + label: ( + + ), + })), + [userReservesSummary.reserves], + ); - const variableBorrowAPR = useMemo(() => { - if (!reserve) return Decimal.from(0); - return Decimal.from(reserve.variableBorrowAPR).mul(100); - }, [reserve]); + const borrowReserve = useMemo(() => { + return userReservesSummary.reserves.find( + r => r.reserve.symbol === borrowAsset, + ); + }, [userReservesSummary.reserves, borrowAsset]); const borrowUsdAmount = useMemo(() => { - return borrowSize.mul(reserve?.priceInUSD ?? 0); - }, [borrowSize, reserve?.priceInUSD]); + return borrowSize.mul(borrowReserve?.reserve.priceInUSD ?? 0); + }, [borrowSize, borrowReserve?.reserve.priceInUSD]); const maximumBorrowAmount = useMemo(() => { - if ( - !reserve?.priceInUSD || - !userReservesSummary?.collateralBalance || - !userReservesSummary?.borrowBalance - ) - return Decimal.from(0); - - // deducted from minCr = coll / (borrowed + maxBorrowed) - return userReservesSummary.collateralBalance - .div(config.MinCollateralRatio) - .sub(userReservesSummary.borrowBalance) - .div(reserve.priceInUSD); + return borrowReserve?.availableToBorrow ?? Decimal.from(0); + }, [borrowReserve?.availableToBorrow]); + + const newCollateralRatio = useMemo(() => { + return AaveCalculations.computeCollateralRatio( + userReservesSummary.collateralBalance, + userReservesSummary.borrowBalance.add(borrowUsdAmount), + ); }, [ - reserve?.priceInUSD, - userReservesSummary?.collateralBalance, - userReservesSummary?.borrowBalance, + userReservesSummary.collateralBalance, + userReservesSummary.borrowBalance, + borrowUsdAmount, ]); - const borrowableAssetsOptions = useMemo( - () => - reserves.map(r => ({ - value: r.symbol, - label: ( - - ), - })), - [reserves], - ); + const liquidationPrice = useMemo(() => { + return AaveCalculations.computeLiquidationPrice( + borrowSize, + userReservesSummary.currentLiquidationThreshold, + userReservesSummary.collateralBalance, + ); + }, [ + borrowSize, + userReservesSummary.currentLiquidationThreshold, + userReservesSummary.collateralBalance, + ]); const isValidBorrowAmount = useMemo( () => (borrowSize.gt(0) ? borrowSize.lte(maximumBorrowAmount) : true), [borrowSize, maximumBorrowAmount], ); - const collateralRatio = useMemo(() => { - if (!userReservesSummary) return Decimal.from(0); - const newHealthFactor = userReservesSummary.healthFactor - .mul(userReservesSummary.borrowBalance) - .div(userReservesSummary.borrowBalance.add(borrowUsdAmount)); - - return newHealthFactor.div(userReservesSummary.currentLiquidationThreshold); - }, [userReservesSummary, borrowUsdAmount]); - - const liquidationPrice = useMemo(() => { - if (!borrowSize || !reserve || !userReservesSummary) { - return Decimal.from(0); - } - - return borrowSize - .mul(userReservesSummary.currentLiquidationThreshold) - .div(userReservesSummary.collateralBalance); - }, [borrowSize, reserve, userReservesSummary]); - - const submitButtonDisabled = useMemo( - () => !isValidBorrowAmount || borrowSize.lte(0) || !acknowledge || !reserve, - [isValidBorrowAmount, borrowSize, acknowledge, reserve], - ); - return (
@@ -150,7 +132,7 @@ export const BorrowForm: FC = ({ asset }) => { label={t(translations.aavePage.borrowForm.borrowApr)} value={ @@ -159,7 +141,7 @@ export const BorrowForm: FC = ({ asset }) => { @@ -180,7 +162,7 @@ export const BorrowForm: FC = ({ asset }) => { })} value={ @@ -204,11 +186,16 @@ export const BorrowForm: FC = ({ asset }) => { onClick={async () => { handleBorrow( borrowSize, - await getAssetData(reserve!.symbol, BOB_CHAIN_ID), + await getAssetData(borrowReserve!.reserve.symbol, BOB_CHAIN_ID), BorrowRateMode.VARIABLE, ); }} - disabled={submitButtonDisabled} + disabled={ + !isValidBorrowAmount || + borrowSize.lte(0) || + !acknowledge || + !borrowReserve + } text={t(translations.common.buttons.confirm)} /> diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx index 2b22e1355..ad0b7dcae 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx @@ -19,13 +19,13 @@ import { AssetAmountInput } from '../../../../../../2_molecules/AssetAmountInput import { AssetRenderer } from '../../../../../../2_molecules/AssetRenderer/AssetRenderer'; import { config } from '../../../../../../../constants/aave'; import { useAaveRepay } from '../../../../../../../hooks/aave/useAaveRepay'; -import { useAaveReservesData } from '../../../../../../../hooks/aave/useAaveReservesData'; import { useAaveUserReservesData } from '../../../../../../../hooks/aave/useAaveUserReservesData'; import { useAccount } from '../../../../../../../hooks/useAccount'; import { useAssetBalance } from '../../../../../../../hooks/useAssetBalance'; import { useDecimalAmountInput } from '../../../../../../../hooks/useDecimalAmountInput'; import { translations } from '../../../../../../../locales/i18n'; import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; +import { AaveCalculations } from '../../../../../../../utils/aave/AaveCalculations'; const pageTranslations = translations.aavePage; @@ -39,7 +39,6 @@ export const RepayWithWalletBalanceForm: FC< > = ({ asset }) => { const { account } = useAccount(); const { handleRepay } = useAaveRepay(); - const reserves = useAaveReservesData(); const userReservesSummary = useAaveUserReservesData(); const [repayAsset, setRepayAsset] = useState(asset); const [repayAmount, setRepayAmount, repaySize] = useDecimalAmountInput(''); @@ -51,67 +50,61 @@ export const RepayWithWalletBalanceForm: FC< const repayAssetsOptions = useMemo( () => - userReservesSummary - ? userReservesSummary.borrowedAssets.map(ba => ({ - value: ba.asset, - label: ( - - ), - })) - : [], + userReservesSummary.reserves + .filter(r => r.borrowed.gt(0)) + .map(ba => ({ + value: ba.asset, + label: ( + + ), + })), [userReservesSummary], ); - const debt = useMemo(() => { - return userReservesSummary?.borrowedAssets.find( - a => a.asset === repayAsset, + const repayReserve = useMemo(() => { + return userReservesSummary.reserves.find( + r => r.reserve.symbol === repayAsset, ); - }, [userReservesSummary, repayAsset]); + }, [userReservesSummary.reserves, repayAsset]); const maximumRepayAmount = useMemo(() => { - return debt - ? debt.borrowed.gt(repayAssetBalance) + return repayReserve + ? repayReserve.borrowed.gt(repayAssetBalance) ? repayAssetBalance - : debt.borrowed + : repayReserve.borrowed : Decimal.from(0); - }, [debt, repayAssetBalance]); - - const reserve = useMemo(() => { - return reserves.find(r => r.symbol === repayAsset); - }, [reserves, repayAsset]); + }, [repayReserve, repayAssetBalance]); const repayUsdAmount = useMemo(() => { - return repaySize.mul(reserve?.priceInUSD ?? 0); - }, [repaySize, reserve]); + return repaySize.mul(repayReserve?.reserve.priceInUSD ?? 0); + }, [repaySize, repayReserve]); const newDebtAmount = useMemo(() => { - const nd = debt?.borrowed ? debt.borrowed.sub(repaySize) : Decimal.from(0); + const nd = repayReserve?.borrowed + ? repayReserve.borrowed.sub(repaySize) + : Decimal.from(0); return nd.gt(0) ? nd : Decimal.from(0); - }, [debt, repaySize]); + }, [repayReserve?.borrowed, repaySize]); const newDebtAmountUSD = useMemo(() => { - return newDebtAmount.mul(reserve?.priceInUSD ?? 0); - }, [newDebtAmount, reserve]); - - const collateralRatio = useMemo(() => { - if (!userReservesSummary) return Decimal.from(0); - - return userReservesSummary.healthFactor.div( - userReservesSummary.currentLiquidationThreshold, - ); - }, [userReservesSummary]); + return newDebtAmount.mul(repayReserve?.reserve.priceInUSD ?? 0); + }, [newDebtAmount, repayReserve]); const newCollateralRatio = useMemo(() => { - if (!userReservesSummary) return Decimal.from(0); - if (newDebtAmountUSD.eq(0)) return Decimal.from('100000000'); - - return userReservesSummary.collateralBalance.div( - userReservesSummary.borrowBalance.add(newDebtAmountUSD), + const newTotalDebtUsd = + userReservesSummary.borrowBalance.add(newDebtAmountUSD); + if (newTotalDebtUsd.eq(0)) { + return Decimal.from('100000000'); // div/0 -> inf + } + + return AaveCalculations.computeCollateralRatio( + userReservesSummary.collateralBalance, + newTotalDebtUsd, ); }, [userReservesSummary, newDebtAmountUSD]); @@ -158,7 +151,7 @@ export const RepayWithWalletBalanceForm: FC< className="justify-end" from={{ precision: 2, - value: debt?.borrowed ?? Decimal.from(0), + value: repayReserve?.borrowed ?? Decimal.from(0), suffix: repayAsset, }} to={{ value: newDebtAmount, suffix: repayAsset, precision: 2 }} @@ -167,7 +160,7 @@ export const RepayWithWalletBalanceForm: FC< className="justify-end text-gray-40" from={{ precision: 2, - value: debt?.borrowedUSD ?? Decimal.from(0), + value: repayReserve?.borrowedUSD ?? Decimal.from(0), prefix: '$', }} to={{ @@ -185,7 +178,7 @@ export const RepayWithWalletBalanceForm: FC< diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawForm/WithdrawForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawForm/WithdrawForm.tsx index 54a8be6cb..9e3a41282 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawForm/WithdrawForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/components/WithdrawForm/WithdrawForm.tsx @@ -34,7 +34,6 @@ type WithdrawFormProps = { export const WithdrawForm: FC = ({ asset }) => { const { handleWithdraw } = useAaveWithdraw(); - const reserves = useAaveReservesData(); const userReservesSummary = useAaveUserReservesData(); const [withdrawAsset, setWithdrawAsset] = useState(asset); const [withdrawAmount, setWithdrawAmount, withdrawSize] = @@ -42,36 +41,37 @@ export const WithdrawForm: FC = ({ asset }) => { const withdrawableAssetsOptions = useMemo( () => - !userReservesSummary - ? [] - : userReservesSummary.suppliedAssets.map(sa => ({ - value: sa.asset, - label: ( - - ), - })), + userReservesSummary.reserves + .filter(r => r.supplied.gt(0)) + .map(sa => ({ + value: sa.asset, + label: ( + + ), + })), [userReservesSummary], ); - const maximumWithdrawAmount: Decimal = useMemo(() => { - if (!userReservesSummary) return Decimal.from(0); - const sa = userReservesSummary.suppliedAssets.find( - sa => sa.asset === withdrawAsset, + const withdrawReserve = useMemo(() => { + return userReservesSummary.reserves.find( + r => r.reserve.symbol === withdrawAsset, ); - return sa ? sa.supplied : Decimal.from(0); - }, [userReservesSummary, withdrawAsset]); + }, [withdrawAsset, userReservesSummary]); - const withdrawAmountUsd: Decimal = useMemo(() => { - if (!reserves) return Decimal.from(0); - const reserve = reserves.find(r => r.symbol === withdrawAsset); + const maximumWithdrawAmount: Decimal = useMemo(() => { + return withdrawReserve ? withdrawReserve.supplied : Decimal.from(0); + }, [withdrawReserve]); - return reserve ? withdrawSize.mul(reserve.priceInUSD) : Decimal.from(0); - }, [withdrawSize, reserves, withdrawAsset]); + const withdrawAmountUsd: Decimal = useMemo(() => { + return withdrawReserve + ? withdrawSize.mul(withdrawReserve.reserve.priceInUSD) + : Decimal.from(0); + }, [withdrawSize, withdrawReserve]); const remainingSupply = useMemo( () => maximumWithdrawAmount.sub(withdrawSize), @@ -88,21 +88,22 @@ export const WithdrawForm: FC = ({ asset }) => { [isValidWithdrawAmount, withdrawSize], ); + const tabItems = useMemo( + () => [ + // For now just withdraw is supported + { + activeClassName: 'text-primary-20', + dataAttribute: 'withdraw', + label: t(translations.common.withdraw), + }, + ], + [], + ); + return (
- +
{ +export const useAaveUserReservesData = (): AaveUserReservesSummary => { const provider = config.provider; const { account } = useAccount(); - const [value, setValue] = useState(null); + const [value, setValue] = useState( + AaveUserReservesSummaryFactory.buildZeroSummary([]), + ); const { value: blockNumber } = useBlockNumber(); const [processedBlock, setProcessedBlock] = useState(); @@ -40,7 +32,7 @@ export const useAaveUserReservesData = (): AaveUserReservesSummary | null => { ); const loadUserReservesData = useCallback(async () => { - if (!account || !uiPoolDataProvider || !provider || !blockNumber) { + if (!account || !provider || !uiPoolDataProvider || !blockNumber) { return null; } @@ -58,49 +50,25 @@ export const useAaveUserReservesData = (): AaveUserReservesSummary | null => { marketReferenceCurrencyPriceInUsd: marketReferencePriceInUsd, } = reservesData.baseCurrencyData; const currentTimestamp = dayjs().unix(); - - const balances: AssetBalance[] = await Promise.all( - reservesData.reservesData.map(async r => { - const asset = await getAssetData(r.symbol, BOB_CHAIN_ID); - - try { - const balance = asset.isNative - ? await provider.getBalance(account) - : await asset.contract(provider).balanceOf(account); - - return { - asset, - balance: BigNumber.from(balance), - balanceDecimal: decimalic( - fromWei(balance.toString(), asset.decimals), - ), - }; - } catch (e) { - return { - asset, - balance: BigNumber.from(0), - balanceDecimal: Decimal.ZERO, - }; - } + const userSummary = formatUserSummary({ + currentTimestamp, + marketReferencePriceInUsd, + marketReferenceCurrencyDecimals, + userReserves: userReservesData.userReserves, + userEmodeCategoryId: userReservesData.userEmodeCategoryId, + formattedReserves: formatReserves({ + currentTimestamp, + marketReferencePriceInUsd, + marketReferenceCurrencyDecimals, + reserves: reservesData.reservesData, }), - ); + }); setValue( - AaveUserReservesSummary.from( - formatUserSummary({ - currentTimestamp, - marketReferencePriceInUsd, - marketReferenceCurrencyDecimals, - userReserves: userReservesData.userReserves, - userEmodeCategoryId: userReservesData.userEmodeCategoryId, - formattedReserves: formatReserves({ - currentTimestamp, - marketReferencePriceInUsd, - marketReferenceCurrencyDecimals, - reserves: reservesData.reservesData, - }), - }), - balances, + await AaveUserReservesSummaryFactory.buildSummary( + provider, + account, + userSummary, ), ); setProcessedBlock(blockNumber); diff --git a/apps/frontend/src/utils/aave/AaveCalculations.ts b/apps/frontend/src/utils/aave/AaveCalculations.ts new file mode 100644 index 000000000..a874c72ff --- /dev/null +++ b/apps/frontend/src/utils/aave/AaveCalculations.ts @@ -0,0 +1,123 @@ +import { Decimal } from '@sovryn/utils'; +import { UserSummary } from './AaveUserReservesSummary'; + +export class AaveCalculations { + static computeNetApy( + weightedSupplyApy: Decimal, + suppliedBalance: Decimal, + weightedBorrowApy: Decimal, + borrowedBalance: Decimal, + netWorthUsd: Decimal, + ): Decimal { + return weightedSupplyApy + .mul(suppliedBalance) + .div(netWorthUsd) + .sub(weightedBorrowApy.mul(borrowedBalance).div(netWorthUsd)); + } + + static computeSuppliedBalance( + reserves: UserSummary['userReservesData'], + ): Decimal { + return reserves.reduce( + (suppliedBalance, r) => suppliedBalance.add(r.underlyingBalanceUSD), + Decimal.from(0), + ); + } + + static computeBorrowedBalance( + reserves: UserSummary['userReservesData'], + ): Decimal { + return reserves.reduce( + (borrowedBalance, r) => borrowedBalance.add(r.totalBorrows), + Decimal.from(0), + ); + } + + static computeBorrowPower( + availableBorrowsUSD: Decimal, + borrowedBalance: Decimal, + ) { + return Decimal.from(availableBorrowsUSD).add(borrowedBalance); + } + + static computeBorrowPowerUsed( + borrowedBalance: Decimal, + borrowPower: Decimal, + ) { + return Decimal.from(borrowedBalance).div(borrowPower).mul(100); + } + + static computeCollateral(reserves: UserSummary['userReservesData']): Decimal { + return reserves.reduce( + (collateral, r) => + collateral.add( + r.usageAsCollateralEnabledOnUser ? r.underlyingBalanceUSD : 0, + ), + Decimal.from(0), + ); + } + + static computeHealthFactor( + collateral: Decimal, + currentLiquidationThreshold: Decimal, + borrowedBalance: Decimal, + ): Decimal { + return collateral.mul(currentLiquidationThreshold).div(borrowedBalance); + } + + static computeCollateralRatio(collateral: Decimal, borrowedBalance: Decimal) { + if (borrowedBalance.eq(0)) { + return Decimal.from(10000000000); // -> inf + } + return collateral.div(borrowedBalance); + } + + static computeWeightedBorrowApy( + reserves: UserSummary['userReservesData'], + ): Decimal { + let totalBorrowedUSD = Decimal.from(0); + let weightedBorrowAPYSum = Decimal.from(0); + + reserves.forEach(reserve => { + const borrowedAmountUSD = Decimal.from(reserve.totalBorrowsUSD); + const borrowAPY = Decimal.from(reserve.reserve.variableBorrowAPY); + + weightedBorrowAPYSum = weightedBorrowAPYSum.add( + borrowAPY.mul(borrowedAmountUSD), + ); + totalBorrowedUSD = totalBorrowedUSD.add(borrowedAmountUSD); + }); + + return weightedBorrowAPYSum.div(totalBorrowedUSD).mul(100); + } + + static computeWeightedSupplyApy( + reserves: UserSummary['userReservesData'], + ): Decimal { + let totalBorrowedUSD = Decimal.from(0); + let weightedBorrowAPYSum = Decimal.from(0); + + reserves.forEach(reserve => { + const borrowedAmountUSD = Decimal.from(reserve.totalBorrowsUSD); + const borrowAPY = Decimal.from(reserve.reserve.supplyAPY); + + weightedBorrowAPYSum = weightedBorrowAPYSum.add( + borrowAPY.mul(borrowedAmountUSD), + ); + totalBorrowedUSD = totalBorrowedUSD.add(borrowedAmountUSD); + }); + + return weightedBorrowAPYSum.div(totalBorrowedUSD).mul(100); + } + + static computeLiquidationPrice( + borrowSize: Decimal, + currentLiquidationThreshold: Decimal, + collateralBalance: Decimal, + ) { + if (collateralBalance.eq(0)) { + return Decimal.from("1000000000"); // -> inf + } + return borrowSize.mul(currentLiquidationThreshold).div(collateralBalance); + } +} diff --git a/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts b/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts index 53f653578..9f9ee6ef2 100644 --- a/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts +++ b/apps/frontend/src/utils/aave/AaveUserReservesSummary.ts @@ -4,10 +4,14 @@ import { FormatUserSummaryResponse, } from '@aave/math-utils'; -import { BigNumber } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; -import { AssetDetailsData } from '@sovryn/contracts'; +import { AssetDetailsData, getAssetData } from '@sovryn/contracts'; import { Decimal } from '@sovryn/utils'; +import { Reserve } from '../../hooks/aave/useAaveReservesData'; +import { BOB_CHAIN_ID } from '../../config/chains'; +import { decimalic, fromWei } from '../math'; +import { AaveCalculations } from './AaveCalculations'; export type UserSummary = FormatUserSummaryResponse< ReserveDataHumanized & FormatReserveUSDResponse @@ -24,232 +28,189 @@ export enum LoanType { VARIABLE = 2, } -export type SuppliedAsset = { +export type ReserveSummary = { + reserve: Reserve; asset: string; - assetAddress: string; - apy: Decimal; - isCollateral: boolean; + + walletBalance: Decimal; + walletBalanceUsd: Decimal; + collateral: boolean; supplied: Decimal; suppliedUSD: Decimal; -}; - -export type BorrowedAsset = { - asset: string; - assetAddress: string; - apy: Decimal; - type: LoanType; borrowed: Decimal; borrowedUSD: Decimal; + borrowMode: LoanType; + availableToBorrow: Decimal; +}; + +export type AaveUserReservesSummary = { + netApy: Decimal; + netWorth: Decimal; + healthFactor: Decimal; + collateralRatio: Decimal; + + supplyBalance: Decimal; + supplyWeightedApy: Decimal; + collateralBalance: Decimal; + currentLiquidationThreshold: Decimal; + + borrowBalance: Decimal; + borrowWeightedApy: Decimal; + borrowPower: Decimal; + borrowPowerUsed: Decimal; + eModeEnabled: boolean; + eModeCategoryId: number; + + reserves: ReserveSummary[]; }; -export class AaveUserReservesSummary { - public netWorth: Decimal; - public netApy: Decimal; - public healthFactor: Decimal; - public supplyBalance: Decimal; - public supplyWeightedApy: Decimal; - public collateralBalance: Decimal; - public currentLiquidationThreshold: Decimal; - public borrowBalance: Decimal; - public borrowWeightedApy: Decimal; - public borrowPower: Decimal; - public borrowPowerUsed: Decimal; - public suppliedAssets: SuppliedAsset[]; - public borrowedAssets: BorrowedAsset[]; - public balances: AssetBalance[]; - public eModeEnabled: boolean; - - constructor( - private readonly userSummary: UserSummary, - balances: AssetBalance[], - ) { - // balances - this.balances = balances; - this.netWorth = Decimal.from(this.userSummary.netWorthUSD); - this.borrowBalance = Decimal.from(this.userSummary.totalBorrowsUSD); - this.supplyBalance = this.computeSuppliedBalance( - this.userSummary.userReservesData, +export class AaveUserReservesSummaryFactory { + static buildZeroSummary(reserves: Reserve[]): AaveUserReservesSummary { + return { + netApy: Decimal.ZERO, + netWorth: Decimal.ZERO, + healthFactor: Decimal.ZERO, + collateralRatio: Decimal.ZERO, + + supplyBalance: Decimal.ZERO, + supplyWeightedApy: Decimal.ZERO, + collateralBalance: Decimal.ZERO, + currentLiquidationThreshold: Decimal.ZERO, + + borrowBalance: Decimal.ZERO, + borrowWeightedApy: Decimal.ZERO, + borrowPower: Decimal.ZERO, + borrowPowerUsed: Decimal.ZERO, + eModeEnabled: false, + eModeCategoryId: 0, + + reserves: reserves.map(r => ({ + reserve: r, + asset: r.symbol, + + walletBalance: Decimal.ZERO, + walletBalanceUsd: Decimal.ZERO, + collateral: false, + supplied: Decimal.ZERO, + suppliedUSD: Decimal.ZERO, + availableToSupply: Decimal.ZERO, + borrowed: Decimal.ZERO, + borrowedUSD: Decimal.ZERO, + borrowMode: LoanType.VARIABLE, + availableToBorrow: Decimal.ZERO, + })), + }; + } + + static async buildSummary( + provider: ethers.providers.Provider, + account: string, + userSummary: UserSummary, + ): Promise { + const netWorth = Decimal.from(userSummary.netWorthUSD); + const borrowBalance = Decimal.from(userSummary.totalBorrowsUSD); + const supplyBalance = AaveCalculations.computeSuppliedBalance( + userSummary.userReservesData, ); - this.collateralBalance = this.computeCollateral( - this.userSummary.userReservesData, + const collateralBalance = AaveCalculations.computeCollateral( + userSummary.userReservesData, ); - - // apy - this.supplyWeightedApy = this.computeWeightedSupplyApy( - this.userSummary.userReservesData, + const supplyWeightedApy = AaveCalculations.computeWeightedSupplyApy( + userSummary.userReservesData, ); - this.borrowWeightedApy = this.computeWeightedBorrowApy( - this.userSummary.userReservesData, + const borrowWeightedApy = AaveCalculations.computeWeightedBorrowApy( + userSummary.userReservesData, ); - this.netApy = this.computeNetApy( - this.supplyWeightedApy, - this.supplyBalance, - this.borrowWeightedApy, - this.borrowBalance, - this.netWorth, + const netApy = AaveCalculations.computeNetApy( + supplyWeightedApy, + supplyBalance, + borrowWeightedApy, + borrowBalance, + netWorth, ); // health and borrow status - this.currentLiquidationThreshold = Decimal.from( - this.userSummary.currentLiquidationThreshold, + const currentLiquidationThreshold = Decimal.from( + userSummary.currentLiquidationThreshold, ); - this.borrowPower = this.computeBorrowPower( - Decimal.from(this.userSummary.availableBorrowsUSD), - this.borrowBalance, + const borrowPower = AaveCalculations.computeBorrowPower( + Decimal.from(userSummary.availableBorrowsUSD), + borrowBalance, ); - this.borrowPowerUsed = this.computeBorrowPowerUsed( - this.borrowBalance, - this.borrowPower, + const borrowPowerUsed = AaveCalculations.computeBorrowPowerUsed( + borrowBalance, + borrowPower, ); - this.healthFactor = this.computeHealthFactor( - this.collateralBalance, - this.currentLiquidationThreshold, - this.borrowBalance, - ); - - // supplied and borrowed assets - this.suppliedAssets = this.computeSuppliedAssets( - this.userSummary.userReservesData, + const healthFactor = AaveCalculations.computeHealthFactor( + collateralBalance, + currentLiquidationThreshold, + borrowBalance, ); - this.borrowedAssets = this.computeBorrowedAssets( - this.userSummary.userReservesData, + const collateralRatio = AaveCalculations.computeCollateralRatio( + collateralBalance, + borrowBalance, ); - // emode - this.eModeEnabled = this.userSummary.userEmodeCategoryId !== 0; - } - - static from( - userSummary: FormatUserSummaryResponse< - ReserveDataHumanized & FormatReserveUSDResponse - >, - balances: AssetBalance[], - ) { - return new AaveUserReservesSummary(userSummary, balances); - } - - private computeNetApy( - weightedSupplyApy: Decimal, - suppliedBalance: Decimal, - weightedBorrowApy: Decimal, - borrowedBalance: Decimal, - netWorthUsd: Decimal, - ): Decimal { - return weightedSupplyApy - .mul(suppliedBalance) - .div(netWorthUsd) - .sub(weightedBorrowApy.mul(borrowedBalance).div(netWorthUsd)); - } - - private computeSuppliedBalance( - reserves: UserSummary['userReservesData'], - ): Decimal { - return reserves.reduce( - (suppliedBalance, r) => suppliedBalance.add(r.underlyingBalanceUSD), - Decimal.from(0), - ); - } - - private computeBorrowPower( - availableBorrowsUSD: Decimal, - borrowedBalance: Decimal, - ) { - return Decimal.from(availableBorrowsUSD).add(borrowedBalance); - } - - private computeBorrowPowerUsed( - borrowedBalance: Decimal, - borrowPower: Decimal, - ) { - return Decimal.from(borrowedBalance).div(borrowPower).mul(100); - } - - private computeCollateral( - reserves: UserSummary['userReservesData'], - ): Decimal { - return reserves.reduce( - (collateral, r) => - collateral.add( - r.usageAsCollateralEnabledOnUser ? r.underlyingBalanceUSD : 0, - ), - Decimal.from(0), - ); - } - - private computeHealthFactor( - collateral: Decimal, - currentLiquidationThreshold: Decimal, - borrowedBalance: Decimal, - ): Decimal { - return collateral.mul(currentLiquidationThreshold).div(borrowedBalance); - } - - private computeWeightedBorrowApy( - reserves: UserSummary['userReservesData'], - ): Decimal { - let totalBorrowedUSD = Decimal.from(0); - let weightedBorrowAPYSum = Decimal.from(0); - - reserves.forEach(reserve => { - const borrowedAmountUSD = Decimal.from(reserve.totalBorrowsUSD); - const borrowAPY = Decimal.from(reserve.reserve.variableBorrowAPY); - - weightedBorrowAPYSum = weightedBorrowAPYSum.add( - borrowAPY.mul(borrowedAmountUSD), - ); - totalBorrowedUSD = totalBorrowedUSD.add(borrowedAmountUSD); - }); - - return weightedBorrowAPYSum.div(totalBorrowedUSD).mul(100); - } - - private computeWeightedSupplyApy( - reserves: UserSummary['userReservesData'], - ): Decimal { - let totalBorrowedUSD = Decimal.from(0); - let weightedBorrowAPYSum = Decimal.from(0); - - reserves.forEach(reserve => { - const borrowedAmountUSD = Decimal.from(reserve.totalBorrowsUSD); - const borrowAPY = Decimal.from(reserve.reserve.supplyAPY); - - weightedBorrowAPYSum = weightedBorrowAPYSum.add( - borrowAPY.mul(borrowedAmountUSD), - ); - totalBorrowedUSD = totalBorrowedUSD.add(borrowedAmountUSD); - }); - - return weightedBorrowAPYSum.div(totalBorrowedUSD).mul(100); - } - - private computeSuppliedAssets( - reserves: UserSummary['userReservesData'], - ): SuppliedAsset[] { - return reserves - .filter(r => Decimal.from(r.underlyingBalanceUSD).gt(0)) - .map(r => ({ - asset: r.reserve.symbol, - assetAddress: r.underlyingAsset, - apy: Decimal.from(r.reserve.supplyAPY).mul(100), - isCollateral: r.usageAsCollateralEnabledOnUser, - supplied: Decimal.from(r.underlyingBalance), - suppliedUSD: Decimal.from(r.underlyingBalanceUSD), - })); + return { + netApy, + netWorth, + healthFactor, + collateralRatio, + + supplyBalance, + supplyWeightedApy, + collateralBalance, + currentLiquidationThreshold, + + borrowBalance, + borrowWeightedApy, + borrowPower, + borrowPowerUsed, + eModeEnabled: userSummary.userEmodeCategoryId !== 0, + eModeCategoryId: userSummary.userEmodeCategoryId, + + reserves: await Promise.all( + userSummary.userReservesData.map(async r => { + const asset = await getAssetData(r.reserve.symbol, BOB_CHAIN_ID); + const balance = await getBalance(asset, account, provider); + const decimalBalance = decimalic(fromWei(balance, asset.decimals)); + + const supplied = Decimal.from(r.underlyingBalance) + const suppliedUSD = Decimal.from(r.underlyingBalanceUSD) + + const borrowed = Decimal.from(r.totalBorrows) + const borrowedUSD = Decimal.from(r.totalBorrowsUSD) + + const availableToBorrow = borrowPower.div(r.reserve.priceInUSD); + + return { + asset: r.reserve.symbol, + reserve: r.reserve, + + walletBalance: decimalBalance, + walletBalanceUsd: decimalBalance.mul(r.reserve.priceInUSD), + collateral: r.usageAsCollateralEnabledOnUser, + supplied, + suppliedUSD, + borrowed, + borrowedUSD, + borrowMode: Decimal.from(r.variableBorrows).gt(0) + ? LoanType.VARIABLE + : LoanType.STABLE, + availableToBorrow, + }; + }), + ), + }; } +} - private computeBorrowedAssets( - reserves: UserSummary['userReservesData'], - ): BorrowedAsset[] { - return reserves - .filter(r => Decimal.from(r.totalBorrowsUSD).gt(0)) - .map(r => ({ - asset: r.reserve.symbol, - assetAddress: r.underlyingAsset, - borrowed: Decimal.from(r.totalBorrows), - borrowedUSD: Decimal.from(r.totalBorrowsUSD), - apy: Decimal.from(r.reserve.variableBorrowAPY).mul(100), - type: - Number(r.variableBorrows) > 0 ? LoanType.VARIABLE : LoanType.STABLE, - })); - } +function getBalance( + asset: AssetDetailsData, + account: string, + provider: ethers.providers.Provider, +): Promise { + return asset.isNative + ? provider.getBalance(account) + : asset.contract(provider).balanceOf(account); } From 0db4ace928b8cb524aa09619254669815e58a845 Mon Sep 17 00:00:00 2001 From: matzapata Date: Wed, 28 Aug 2024 17:38:31 +0300 Subject: [PATCH 16/22] implementations and cleanup --- .../src/app/5_pages/AavePage/AavePage.tsx | 13 +++--- .../app/5_pages/AavePage/AavePage.utils.tsx | 16 ++++---- .../BorrowModal/BorrowForm.utils.ts | 34 ---------------- .../BorrowPositionsList.constants.tsx | 4 +- .../BorrowPositionsList.types.tsx | 4 +- .../BorrowPositionDetails.tsx | 4 +- .../RepayForm/RepayWithWalletBalanceForm.tsx | 4 +- .../components/LendForm/LendForm.tsx | 16 +++----- .../components/WithdrawForm/WithdrawForm.tsx | 1 - apps/frontend/src/hooks/aave/useAaveRepay.tsx | 7 ++-- .../src/hooks/aave/useAaveReservesData.tsx | 3 +- .../hooks/aave/useAaveUserReservesData.tsx | 6 ++- .../aave/AaveRepayTransactionsFactory.ts | 17 ++++---- .../src/utils/aave/AaveUserReservesSummary.ts | 40 ++++++------------- 14 files changed, 55 insertions(+), 114 deletions(-) delete mode 100644 apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.utils.ts diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx index a0d2da114..2a0145ace 100644 --- a/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.tsx @@ -41,23 +41,20 @@ const AavePage: FC = () => { () => normalizeLendPositions(userReservesSummary), [userReservesSummary], ); - const borrowPositions: BorrowPosition[] = useMemo( () => normalizeBorrowPositions(userReservesSummary), [userReservesSummary], ); - const borrowPools: BorrowPoolDetails[] = useMemo( () => normalizeBorrowPoolDetails(reserves, userReservesSummary), [reserves, userReservesSummary], ); - - const lendPools: LendPoolDetails[] = normalizeLendPoolDetails( - reserves, - userReservesSummary, + const lendPools: LendPoolDetails[] = useMemo( + () => normalizeLendPoolDetails(reserves, userReservesSummary), + [reserves, userReservesSummary], ); - const items = useMemo( + const tabsItems = useMemo( () => [ { activeClassName: 'text-primary-20', @@ -90,7 +87,7 @@ const AavePage: FC = () => { setActiveTab(e)} size={TabSize.normal} type={TabType.secondary} diff --git a/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx b/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx index b81129f88..f7c0fbc06 100644 --- a/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/AavePage.utils.tsx @@ -1,10 +1,8 @@ import { Decimal } from '@sovryn/utils'; import { ReserveData } from '../../../hooks/aave/useAaveReservesData'; -import { - AaveUserReservesSummary, - LoanType, -} from '../../../utils/aave/AaveUserReservesSummary'; +import { BorrowRateMode } from '../../../types/aave'; +import { AaveUserReservesSummary } from '../../../utils/aave/AaveUserReservesSummary'; import { BorrowPosition } from './components/BorrowPositionsList/BorrowPositionsList.types'; import { LendPosition } from './components/LendPositionsList/LendPositionsList.types'; @@ -30,13 +28,13 @@ export function normalizeBorrowPositions( .map(r => ({ asset: r.reserve.symbol, apy: Decimal.from( - r.borrowMode === LoanType.STABLE + r.borrowRateMode === BorrowRateMode.STABLE ? Decimal.from(r.reserve.stableBorrowAPY).mul(100) : Decimal.from(r.reserve.variableBorrowAPY).mul(100), ), borrowed: r.borrowed, borrowedUSD: r.borrowedUSD, - type: r.borrowMode, + type: r.borrowRateMode, })); } @@ -44,7 +42,7 @@ export function normalizeBorrowPoolDetails( reserves: ReserveData, userReservesSummary: AaveUserReservesSummary, ) { - if (!userReservesSummary) { + if (userReservesSummary.reserves.length === 0) { return reserves .filter(r => r.borrowingEnabled) .map(r => ({ @@ -65,9 +63,9 @@ export function normalizeBorrowPoolDetails( export function normalizeLendPoolDetails( reserves: ReserveData, - userReservesSummary: AaveUserReservesSummary | null, + userReservesSummary: AaveUserReservesSummary, ) { - if (!userReservesSummary) { + if (userReservesSummary.reserves.length === 0) { return reserves.map(r => ({ asset: r.symbol, apy: Decimal.from(r.supplyAPY).mul(100), diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.utils.ts b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.utils.ts deleted file mode 100644 index 7b5be4fbf..000000000 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Decimal } from '@sovryn/utils'; - -import { Reserve } from '../../../../../../../hooks/aave/useAaveReservesData'; - -export const getCollateralRatioThresholds = ( - reserve: Reserve | undefined, - eModeEnabled: boolean, -) => { - let minimumCollateralRatio: Decimal; - if (reserve !== undefined) { - minimumCollateralRatio = eModeEnabled - ? Decimal.from(reserve.formattedEModeLiquidationThreshold) - : Decimal.from(reserve.formattedReserveLiquidationThreshold); - } else { - minimumCollateralRatio = Decimal.from(1); - } - - const threeholds = { - START: minimumCollateralRatio.mul(0.9).toNumber(), - MIDDLE_START: minimumCollateralRatio.toNumber(), - MIDDLE_END: minimumCollateralRatio.mul(1.2).toNumber(), - END: minimumCollateralRatio.mul(1.6).toNumber(), - }; - - // rule of 3 basically END -> 100; {} -> x => x = {} * 100 / END - const scalingFactor = 100 / threeholds.END; - - return { - START: threeholds.START * scalingFactor, - MIDDLE_START: threeholds.MIDDLE_START * scalingFactor, - MIDDLE_END: threeholds.MIDDLE_END * scalingFactor, - END: 100, - }; -}; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx index 6b983f0de..2a56f3d48 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.constants.tsx @@ -9,7 +9,7 @@ import { BOB_CHAIN_ID } from '../../../../../config/chains'; import { AmountRenderer } from '../../../../2_molecules/AmountRenderer/AmountRenderer'; import { AssetRenderer } from '../../../../2_molecules/AssetRenderer/AssetRenderer'; import { translations } from '../../../../../locales/i18n'; -import { LoanType } from '../../../../../utils/aave/AaveUserReservesSummary'; +import { BorrowRateMode } from '../../../../../types/aave'; import { BorrowPosition } from './BorrowPositionsList.types'; import { BorrowPositionAction } from './components/BorrowPositionAction/BorrowPositionAction'; @@ -78,7 +78,7 @@ export const COLUMNS_CONFIG = (onRepayClick: (asset: string) => unknown) => [ {t( pageTranslations.common[ - position.type === LoanType.STABLE ? 'stable' : 'variable' + position.type === BorrowRateMode.STABLE ? 'stable' : 'variable' ], )} diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.types.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.types.tsx index 8445cf994..4b632e359 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.types.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.types.tsx @@ -1,11 +1,11 @@ import { Decimal } from '@sovryn/utils'; -import { LoanType } from '../../../../../utils/aave/AaveUserReservesSummary'; +import { BorrowRateMode } from '../../../../../types/aave'; export type BorrowPosition = { asset: string; borrowed: Decimal; borrowedUSD: Decimal; apy: Decimal; - type: LoanType; + type: BorrowRateMode; }; diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx index dadd985f5..987274d01 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/BorrowPositionDetails/BorrowPositionDetails.tsx @@ -7,7 +7,7 @@ import { HelperButton, SimpleTableRow } from '@sovryn/ui'; import { AmountRenderer } from '../../../../../../2_molecules/AmountRenderer/AmountRenderer'; import { AssetAmountPriceRenderer } from '../../../../../../2_molecules/AssetAmountPriceRenderer/AssetAmountPriceRenderer'; import { translations } from '../../../../../../../locales/i18n'; -import { LoanType } from '../../../../../../../utils/aave/AaveUserReservesSummary'; +import { BorrowRateMode } from '../../../../../../../types/aave'; import { BorrowPosition } from '../../BorrowPositionsList.types'; import { BorrowPositionAction } from '../BorrowPositionAction/BorrowPositionAction'; @@ -53,7 +53,7 @@ export const BorrowPositionDetails: FC = ({ label={t(translations.aavePage.common.apyType)} value={t( translations.aavePage.common[ - position.type === LoanType.STABLE ? 'stable' : 'variable' + position.type === BorrowRateMode.STABLE ? 'stable' : 'variable' ], )} /> diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx index ad0b7dcae..bee58a0fd 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx @@ -24,8 +24,8 @@ import { useAccount } from '../../../../../../../hooks/useAccount'; import { useAssetBalance } from '../../../../../../../hooks/useAssetBalance'; import { useDecimalAmountInput } from '../../../../../../../hooks/useDecimalAmountInput'; import { translations } from '../../../../../../../locales/i18n'; -import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; import { AaveCalculations } from '../../../../../../../utils/aave/AaveCalculations'; +import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; const pageTranslations = translations.aavePage; @@ -201,7 +201,7 @@ export const RepayWithWalletBalanceForm: FC< handleRepay( repaySize, await getAssetData(repayAsset, BOB_CHAIN_ID), - repayReserve!.borrowMode, + repayReserve!.borrowRateMode, ); }} /> diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx index ff8798010..f5709129e 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx @@ -66,20 +66,15 @@ export const LendForm: FC = ({ [reserves], ); + const assetUsdValue: Decimal = useMemo(() => { + return Decimal.from(reserve?.priceInUSD ?? 0).mul(lendSize); + }, [reserve, lendSize]); + const isValidLendAmount = useMemo( () => (lendSize.gt(0) ? lendSize.lte(lendAssetBalance) : true), [lendSize, lendAssetBalance], ); - const submitButtonDisabled = useMemo( - () => !isValidLendAmount || lendSize.lte(0), - [isValidLendAmount, lendSize], - ); - - const assetUsdValue: Decimal = useMemo(() => { - return Decimal.from(reserve?.priceInUSD ?? 0).mul(lendSize); - }, [reserve, lendSize]); - return (
@@ -127,11 +122,12 @@ export const LendForm: FC = ({
@@ -118,11 +118,11 @@ const AavePage: FC = () => { )} >
diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx index 48630e3cc..fc6f6b3db 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.constants.tsx @@ -71,7 +71,7 @@ export const COLUMNS_CONFIG = (onBorrowClick: (asset: string) => void) => [ ), cellRenderer: (pool: BorrowPoolDetails) => ( - + ), }, { diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx index 2117adf64..e0951e8ae 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/BorrowAssetsList.tsx @@ -47,7 +47,7 @@ export const BorrowAssetsList: FC = ({ asset={r.asset} value={r.apy} suffix="%" - label="APY" + label={translations.aavePage.common.apy} precision={2} /> ), diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx index e6b91f225..0c72b7cdd 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowAssetDetails/BorrowAssetDetails.tsx @@ -32,7 +32,7 @@ export const BorrowAssetDetails: FC = ({ } - value={} + value={} /> {/* Available */} diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx index a64e65b1b..40805ab37 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowAssetsList/components/BorrowModal/BorrowForm.tsx @@ -25,17 +25,17 @@ import { useAaveUserReservesData } from '../../../../../../../hooks/aave/useAave import { useDecimalAmountInput } from '../../../../../../../hooks/useDecimalAmountInput'; import { translations } from '../../../../../../../locales/i18n'; import { BorrowRateMode } from '../../../../../../../types/aave'; -import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; import { AaveCalculations } from '../../../../../../../utils/aave/AaveCalculations'; +import { CollateralRatioHealthBar } from '../../../CollateralRatioHealthBar/CollateralRatioHealthBar'; const pageTranslations = translations.aavePage; type BorrowFormProps = { asset: string; - onSuccess: () => unknown; + onSuccess: () => void; }; -export const BorrowForm: FC = ({ asset }) => { +export const BorrowForm: FC = ({ asset, onSuccess }) => { const userReservesSummary = useAaveUserReservesData(); const [borrowAsset, setBorrowAsset] = useState(asset); const [borrowAmount, setBorrowAmount, borrowSize] = useDecimalAmountInput(''); @@ -133,7 +133,7 @@ export const BorrowForm: FC = ({ asset }) => { value={ } @@ -149,11 +149,7 @@ export const BorrowForm: FC = ({ asset }) => { + } /> = ({ asset }) => { } /> @@ -188,6 +184,7 @@ export const BorrowForm: FC = ({ asset }) => { borrowSize, await getAssetData(borrowReserve!.reserve.symbol, BOB_CHAIN_ID), BorrowRateMode.VARIABLE, + { onComplete: onSuccess }, ); }} disabled={ diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx index ee9e999a7..16e5a3279 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/BorrowPositionsList.tsx @@ -27,9 +27,9 @@ const pageTranslations = translations.aavePage; type BorrowPositionsListProps = { borrowPositions: BorrowPosition[]; - borrowBalance?: Decimal; - borrowWeightedApy?: Decimal; - borrowPowerUsed?: Decimal; + borrowBalance: Decimal; + borrowWeightedApy: Decimal; + borrowPowerUsed: Decimal; eModeEnabled: boolean; }; @@ -102,19 +102,19 @@ export const BorrowPositionsList: FC = ({
diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx index 52896d915..ad48869e4 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayForm.tsx @@ -21,7 +21,7 @@ enum RepayWith { export const RepayForm: FC = ({ asset, onSuccess }) => { const [activeTab, setActiveTab] = useState(RepayWith.BALANCE); - const items = useMemo(() => { + const tabItems = useMemo(() => { return [ { activeClassName: 'text-primary-20', @@ -51,7 +51,7 @@ export const RepayForm: FC = ({ asset, onSuccess }) => { contentClassName="p-4" index={activeTab} onChange={setActiveTab} - items={items} + items={tabItems} type={TabType.secondary} /> diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx index bee58a0fd..ffe9e86a9 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx @@ -36,7 +36,7 @@ type RepayWithWalletBalanceFormProps = { export const RepayWithWalletBalanceForm: FC< RepayWithWalletBalanceFormProps -> = ({ asset }) => { +> = ({ asset, onSuccess }) => { const { account } = useAccount(); const { handleRepay } = useAaveRepay(); const userReservesSummary = useAaveUserReservesData(); @@ -202,6 +202,7 @@ export const RepayWithWalletBalanceForm: FC< repaySize, await getAssetData(repayAsset, BOB_CHAIN_ID), repayReserve!.borrowRateMode, + { onComplete: onSuccess }, ); }} /> diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx index 2fc555ad9..265a9fab9 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/LendAssetsList.tsx @@ -50,7 +50,7 @@ export const LendAssetsList: FC = ({ lendPools }) => { asset={r.asset} value={r.apy} suffix="%" - label="APY" + label={translations.aavePage.common.apy} precision={2} /> ), diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx index f5709129e..972ae3e11 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendAssetsList/components/LendForm/LendForm.tsx @@ -46,10 +46,6 @@ export const LendForm: FC = ({ ); const { handleDeposit } = useAaveSupply(); - const reserve = useMemo(() => { - return reserves.find(r => r.symbol === lendAsset) ?? reserves[0]; - }, [reserves, lendAsset]); - const lendAssetsOptions = useMemo( () => reserves.map(r => ({ @@ -66,6 +62,10 @@ export const LendForm: FC = ({ [reserves], ); + const reserve = useMemo(() => { + return reserves.find(r => r.symbol === lendAsset) ?? reserves[0]; + }, [reserves, lendAsset]); + const assetUsdValue: Decimal = useMemo(() => { return Decimal.from(reserve?.priceInUSD ?? 0).mul(lendSize); }, [reserve, lendSize]); diff --git a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx index 991a353e7..434dfd3ea 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/LendPositionsList/LendPositionsList.tsx @@ -26,9 +26,9 @@ import { WithdrawForm } from './components/WithdrawForm/WithdrawForm'; const pageTranslations = translations.aavePage; type LendPositionsListProps = { - supplyBalance?: Decimal; - supplyWeightedApy?: Decimal; - collateralBalance?: Decimal; + supplyBalance: Decimal; + supplyWeightedApy: Decimal; + collateralBalance: Decimal; lendPositions: LendPosition[]; }; @@ -90,20 +90,20 @@ export const LendPositionsList: FC = ({
diff --git a/apps/frontend/src/app/5_pages/AavePage/components/TopPanel/TopPanel.tsx b/apps/frontend/src/app/5_pages/AavePage/components/TopPanel/TopPanel.tsx index 1dacbc811..86b8a9723 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/TopPanel/TopPanel.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/TopPanel/TopPanel.tsx @@ -13,9 +13,9 @@ import { translations } from '../../../../../locales/i18n'; const pageTranslations = translations.aavePage.topPanel; type TopPanelProps = { - netWorth?: Decimalish; - netApy?: Decimalish; - healthFactor?: Decimalish; + netWorth: Decimalish; + netApy: Decimalish; + healthFactor: Decimalish; }; export const TopPanel: FC = ({ @@ -41,7 +41,7 @@ export const TopPanel: FC = ({ = ({ = ({ Date: Wed, 28 Aug 2024 18:04:13 +0300 Subject: [PATCH 19/22] math safety --- .../src/utils/aave/AaveCalculations.ts | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/frontend/src/utils/aave/AaveCalculations.ts b/apps/frontend/src/utils/aave/AaveCalculations.ts index a874c72ff..e6f244ec7 100644 --- a/apps/frontend/src/utils/aave/AaveCalculations.ts +++ b/apps/frontend/src/utils/aave/AaveCalculations.ts @@ -1,4 +1,5 @@ import { Decimal } from '@sovryn/utils'; + import { UserSummary } from './AaveUserReservesSummary'; export class AaveCalculations { @@ -44,6 +45,9 @@ export class AaveCalculations { borrowedBalance: Decimal, borrowPower: Decimal, ) { + if (borrowPower.eq(0)) { + return Decimal.from(100); // all used + } return Decimal.from(borrowedBalance).div(borrowPower).mul(100); } @@ -62,12 +66,15 @@ export class AaveCalculations { currentLiquidationThreshold: Decimal, borrowedBalance: Decimal, ): Decimal { + if (borrowedBalance.eq(0)) { + return Decimal.from(Infinity); + } return collateral.mul(currentLiquidationThreshold).div(borrowedBalance); } static computeCollateralRatio(collateral: Decimal, borrowedBalance: Decimal) { if (borrowedBalance.eq(0)) { - return Decimal.from(10000000000); // -> inf + return Decimal.from(Infinity); } return collateral.div(borrowedBalance); } @@ -88,26 +95,32 @@ export class AaveCalculations { totalBorrowedUSD = totalBorrowedUSD.add(borrowedAmountUSD); }); + if (totalBorrowedUSD.eq(0) || weightedBorrowAPYSum.eq(0)) { + return Decimal.from(0); + } return weightedBorrowAPYSum.div(totalBorrowedUSD).mul(100); } static computeWeightedSupplyApy( reserves: UserSummary['userReservesData'], ): Decimal { - let totalBorrowedUSD = Decimal.from(0); - let weightedBorrowAPYSum = Decimal.from(0); + let totalSuppliedUSD = Decimal.from(0); + let weightedSupplyAPYSum = Decimal.from(0); reserves.forEach(reserve => { - const borrowedAmountUSD = Decimal.from(reserve.totalBorrowsUSD); - const borrowAPY = Decimal.from(reserve.reserve.supplyAPY); + const suppliedAmountUSD = Decimal.from(reserve.underlyingBalanceUSD); + const supplyAPY = Decimal.from(reserve.reserve.supplyAPY); - weightedBorrowAPYSum = weightedBorrowAPYSum.add( - borrowAPY.mul(borrowedAmountUSD), + weightedSupplyAPYSum = weightedSupplyAPYSum.add( + supplyAPY.mul(suppliedAmountUSD), ); - totalBorrowedUSD = totalBorrowedUSD.add(borrowedAmountUSD); + totalSuppliedUSD = totalSuppliedUSD.add(suppliedAmountUSD); }); - return weightedBorrowAPYSum.div(totalBorrowedUSD).mul(100); + if (totalSuppliedUSD.eq(0) || weightedSupplyAPYSum.eq(0)) { + return Decimal.from(0); + } + return weightedSupplyAPYSum.div(totalSuppliedUSD).mul(100); } static computeLiquidationPrice( @@ -116,7 +129,7 @@ export class AaveCalculations { collateralBalance: Decimal, ) { if (collateralBalance.eq(0)) { - return Decimal.from("1000000000"); // -> inf + return Decimal.from(Infinity); } return borrowSize.mul(currentLiquidationThreshold).div(collateralBalance); } From 400af737f1b7516bb0e1bf8617673a3b5b0cfb77 Mon Sep 17 00:00:00 2001 From: matzapata Date: Wed, 28 Aug 2024 18:05:59 +0300 Subject: [PATCH 20/22] more math safety --- apps/frontend/src/utils/aave/AaveCalculations.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/utils/aave/AaveCalculations.ts b/apps/frontend/src/utils/aave/AaveCalculations.ts index e6f244ec7..391509699 100644 --- a/apps/frontend/src/utils/aave/AaveCalculations.ts +++ b/apps/frontend/src/utils/aave/AaveCalculations.ts @@ -10,6 +10,10 @@ export class AaveCalculations { borrowedBalance: Decimal, netWorthUsd: Decimal, ): Decimal { + if (netWorthUsd.eq(0)) { + return Decimal.from(0); + } + return weightedSupplyApy .mul(suppliedBalance) .div(netWorthUsd) @@ -129,7 +133,7 @@ export class AaveCalculations { collateralBalance: Decimal, ) { if (collateralBalance.eq(0)) { - return Decimal.from(Infinity); + return Decimal.from(Infinity); // get liquidated right away } return borrowSize.mul(currentLiquidationThreshold).div(collateralBalance); } From d5318dab8cb7c9687f96930678a6a4d38f303e44 Mon Sep 17 00:00:00 2001 From: matzapata Date: Wed, 28 Aug 2024 18:09:18 +0300 Subject: [PATCH 21/22] cleanup --- .../components/RepayForm/RepayWithWalletBalanceForm.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx index ffe9e86a9..c1cb03b07 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx @@ -96,15 +96,9 @@ export const RepayWithWalletBalanceForm: FC< }, [newDebtAmount, repayReserve]); const newCollateralRatio = useMemo(() => { - const newTotalDebtUsd = - userReservesSummary.borrowBalance.add(newDebtAmountUSD); - if (newTotalDebtUsd.eq(0)) { - return Decimal.from('100000000'); // div/0 -> inf - } - return AaveCalculations.computeCollateralRatio( userReservesSummary.collateralBalance, - newTotalDebtUsd, + userReservesSummary.borrowBalance.add(newDebtAmountUSD), ); }, [userReservesSummary, newDebtAmountUSD]); From 2a0c7b9777d39eb2ac2116fccc0f416bca666621 Mon Sep 17 00:00:00 2001 From: matzapata Date: Wed, 28 Aug 2024 18:13:32 +0300 Subject: [PATCH 22/22] clenaup --- .../components/RepayForm/RepayWithWalletBalanceForm.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx index c1cb03b07..8511f7681 100644 --- a/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx +++ b/apps/frontend/src/app/5_pages/AavePage/components/BorrowPositionsList/components/RepayForm/RepayWithWalletBalanceForm.tsx @@ -85,10 +85,12 @@ export const RepayWithWalletBalanceForm: FC< }, [repaySize, repayReserve]); const newDebtAmount = useMemo(() => { - const nd = repayReserve?.borrowed + const newDebt = repayReserve?.borrowed ? repayReserve.borrowed.sub(repaySize) : Decimal.from(0); - return nd.gt(0) ? nd : Decimal.from(0); + + // avoid negatives: + return newDebt.gt(0) ? newDebt : Decimal.from(0); }, [repayReserve?.borrowed, repaySize]); const newDebtAmountUSD = useMemo(() => {