Skip to content

Commit

Permalink
fix(Loans): simplify form and hook (#1476)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsimao authored Jul 20, 2023
1 parent 5c6a8df commit 56f45b0
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 77 deletions.
77 changes: 24 additions & 53 deletions src/pages/Loans/LoansOverview/components/LoanForm/LoanForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { BorrowPosition, CollateralPosition, CurrencyExt, LoanAsset, newMonetaryAmount } from '@interlay/interbtc-api';
import { MonetaryAmount } from '@interlay/monetary-js';
import { mergeProps } from '@react-aria/utils';
import { ChangeEventHandler, RefObject, useCallback, useState } from 'react';
import { RefObject, useCallback } from 'react';
import { TFunction, useTranslation } from 'react-i18next';
import { useDebounce } from 'react-use';

import { convertMonetaryAmountToValueInUSD, newSafeMonetaryAmount } from '@/common/utils/utils';
import { Flex, TokenInput } from '@/component-library';
Expand All @@ -29,6 +28,12 @@ import { BorrowLimit } from '../BorrowLimit';
import { LoanDetails } from '../LoanDetails';
import { StyledFormWrapper } from './LoanForm.style';

const isMaxWithdrawAmount = (amount: MonetaryAmount<CurrencyExt>, position?: BorrowPosition | CollateralPosition) =>
!!position?.amount.eq(amount);

const isMaxRepayAmount = (amount: MonetaryAmount<CurrencyExt>, maxAmount: MonetaryAmount<CurrencyExt>) =>
maxAmount.eq(amount);

// The borrow limit component is only displayed when
// loan form is openned while lending an asset that is
// being used as collateral or while borrowing an asset
Expand Down Expand Up @@ -86,9 +91,6 @@ type LoanFormProps = {
};

const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan }: LoanFormProps): JSX.Element => {
const [inputAmount, setInputAmount] = useState<string>();
const [isMaxAmount, setMaxAmount] = useState(false);

const { t } = useTranslation();
const {
refetch,
Expand All @@ -99,32 +101,6 @@ const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan

const { content } = getData(t, variant);

// withdraw has `withdraw` and `withdrawAll`
// repay has `repay` and `repayAll`
// They both are considered a multi action variant
const hasMultiActionVariant = variant === 'withdraw' || variant === 'repay';

const handleMaxAmount = (amount: MonetaryAmount<CurrencyExt>) => {
// Comparing if the provided amount is equal to the amount
// available for the action, which is only relevant for
// when the action is `withdraw` or `repay`
const isMaxAmount = variant === 'withdraw' ? !!position?.amount.eq(amount) : assetAmount.max.eq(amount);

setMaxAmount(isMaxAmount);
};

useDebounce(
() => {
if (!inputAmount || !hasMultiActionVariant) return;

const inputMonetary = newMonetaryAmount(inputAmount, asset.currency, true);

handleMaxAmount(inputMonetary);
},
300,
[inputAmount]
);

const transaction = useTransaction({ onSigning: onChangeLoan, onSuccess: refetch });

const getTransactionArgs = useCallback(
Expand All @@ -151,20 +127,26 @@ const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan
switch (variant) {
case 'lend':
return transaction.execute(Transaction.LOANS_LEND, monetaryAmount.currency, monetaryAmount);
case 'withdraw':
if (isMaxAmount) {
case 'withdraw': {
const isWithdrawAll = isMaxWithdrawAmount(monetaryAmount, position);

if (isWithdrawAll) {
return transaction.execute(Transaction.LOANS_WITHDRAW_ALL, monetaryAmount.currency);
} else {
return transaction.execute(Transaction.LOANS_WITHDRAW, monetaryAmount.currency, monetaryAmount);
}
}
case 'borrow':
return transaction.execute(Transaction.LOANS_BORROW, monetaryAmount.currency, monetaryAmount);
case 'repay':
if (isMaxAmount) {
case 'repay': {
const isRepayAll = isMaxRepayAmount(monetaryAmount, assetAmount.max);

if (isRepayAll) {
return transaction.execute(Transaction.LOANS_REPAY_ALL, monetaryAmount.currency, assetAmount.available);
} else {
return transaction.execute(Transaction.LOANS_REPAY, monetaryAmount.currency, monetaryAmount);
}
}
}
};

Expand All @@ -188,7 +170,9 @@ const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan
case 'lend':
return transaction.fee.estimate(Transaction.LOANS_LEND, monetaryAmount.currency, monetaryAmount);
case 'withdraw': {
if (isMaxAmount) {
const isWithdrawAll = isMaxWithdrawAmount(monetaryAmount, position);

if (isWithdrawAll) {
return transaction.fee.estimate(Transaction.LOANS_WITHDRAW_ALL, monetaryAmount.currency);
} else {
return transaction.fee.estimate(Transaction.LOANS_WITHDRAW, monetaryAmount.currency, monetaryAmount);
Expand All @@ -198,7 +182,9 @@ const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan
return transaction.fee.estimate(Transaction.LOANS_BORROW, monetaryAmount.currency, monetaryAmount);

case 'repay': {
if (isMaxAmount) {
const isRepayAll = isMaxRepayAmount(monetaryAmount, assetAmount.max);

if (isRepayAll) {
return (
transaction.fee
// passing the limit calculated, so it can be used in the validation in transaction hook
Expand All @@ -216,19 +202,6 @@ const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan

const isBtnDisabled = isTransactionFormDisabled(form, transaction.fee);

const handleClickBalance = () => {
if (!hasMultiActionVariant) return;

handleMaxAmount(assetAmount.available);
};

const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {
if (!hasMultiActionVariant) return;

setMaxAmount(false);
setInputAmount(e.target.value);
};

const showBorrowLimit = shouldShowBorrowLimit(variant, hasCollateral, position);

return (
Expand All @@ -241,11 +214,9 @@ const LoanForm = ({ asset, variant, position, overlappingModalRef, onChangeLoan
aria-label={content.fieldAriaLabel}
balanceLabel={content.label}
valueUSD={convertMonetaryAmountToValueInUSD(monetaryAmount, assetPrice) ?? 0}
onClickBalance={handleClickBalance}
{...mergeProps(
form.getFieldProps(LOAN_AMOUNT_FIELD, false, true),
getTokenInputProps(assetAmount.available),
{ onChange: handleChange }
getTokenInputProps(assetAmount.available)
)}
/>
{showBorrowLimit && (
Expand Down
2 changes: 2 additions & 0 deletions src/test/pages/Swap.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const { getLiquidityProvidedByAccount, swap } = MOCK_AMM.MODULE;
const { BLOCK_NUMBER } = MOCK_SYSTEM.DATA;
const { getFutureBlockNumber } = MOCK_SYSTEM.MODULE;

jest.useFakeTimers();

const path = '/swap';

jest.mock('../../parts/Layout', () => {
Expand Down
29 changes: 5 additions & 24 deletions src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import {
BorrowPosition,
CollateralPosition,
CurrencyExt,
LendingStats,
LoanAsset,
TickerToData
} from '@interlay/interbtc-api';
import { MonetaryAmount } from '@interlay/monetary-js';
import { BorrowPosition, CollateralPosition, LendingStats, LoanAsset, TickerToData } from '@interlay/interbtc-api';
import Big from 'big.js';
import { useMemo } from 'react';

Expand All @@ -17,7 +9,6 @@ import { useGetLoanAssets } from '@/utils/hooks/api/loans/use-get-loan-assets';

import { Prices, useGetPrices } from '../use-get-prices';
import { useGetAccountPositions } from './use-get-account-positions';
import { useGetAccountSubsidyRewards } from './use-get-account-subsidy-rewards';

interface AccountLendingStatistics extends LendingStats {
supplyAmountUSD: Big;
Expand Down Expand Up @@ -78,12 +69,12 @@ const getAccountPositionsStats = (
assets: TickerToData<LoanAsset>,
lendPositions: CollateralPosition[],
borrowPositions: BorrowPosition[],
subsidyRewards: MonetaryAmount<CurrencyExt>,
prices: Prices,
lendingStats: LendingStats
): AccountLendingStatistics => {
const { totalLentBtc, totalBorrowedBtc, totalCollateralBtc } = lendingStats;
// Convert from BTC to USD values.

const supplyAmountUSD = convertMonetaryBtcToUSD(totalLentBtc, prices);
const borrowAmountUSD = convertMonetaryBtcToUSD(totalBorrowedBtc, prices);
const collateralizedAmountUSD = convertMonetaryBtcToUSD(totalCollateralBtc, prices);
Expand All @@ -109,8 +100,6 @@ const useGetAccountLendingStatistics = (): UseGetAccountLendingStatistics => {

const prices = useGetPrices();

const { data: subsidyRewards, refetch: subsidyRewardsRefetch } = useGetAccountSubsidyRewards();

const lendingStats = useMemo(() => {
if (!lendPositions || !borrowPositions || !loanAssets) {
return undefined;
Expand All @@ -119,26 +108,18 @@ const useGetAccountLendingStatistics = (): UseGetAccountLendingStatistics => {
}, [lendPositions, borrowPositions, loanAssets]);

const statistics = useMemo(() => {
if (!loanAssets || !lendPositions || !borrowPositions || !subsidyRewards || !prices || !lendingStats) {
if (!loanAssets || !lendPositions || !borrowPositions || !prices || !lendingStats) {
return undefined;
}

return getAccountPositionsStats(
loanAssets,
lendPositions,
borrowPositions,
subsidyRewards.total,
prices,
lendingStats
);
}, [lendPositions, borrowPositions, prices, subsidyRewards, loanAssets, lendingStats]);
return getAccountPositionsStats(loanAssets, lendPositions, borrowPositions, prices, lendingStats);
}, [lendPositions, borrowPositions, prices, loanAssets, lendingStats]);

return {
data: statistics,
refetch: () => {
positionsRefetch();
loanAssetsRefetch();
subsidyRewardsRefetch();
}
};
};
Expand Down

2 comments on commit 56f45b0

@vercel
Copy link

@vercel vercel bot commented on 56f45b0 Jul 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 56f45b0 Jul 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.