mars-v2-frontend/src/components/Modals/v1/Repay.tsx
2024-02-15 21:51:00 +01:00

209 lines
7.2 KiB
TypeScript

import BigNumber from 'bignumber.js'
import { useCallback, useEffect, useMemo, useState } from 'react'
import Modal from 'components/Modals/Modal'
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
import Button from 'components/common/Button'
import Card from 'components/common/Card'
import DisplayCurrency from 'components/common/DisplayCurrency'
import Divider from 'components/common/Divider'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight, InfoCircle } from 'components/common/Icons'
import Text from 'components/common/Text'
import TitleAndSubCell from 'components/common/TitleAndSubCell'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import AssetImage from 'components/common/assets/AssetImage'
import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useMarkets from 'hooks/markets/useMarkets'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { formatPercent } from 'utils/formatters'
import { BN } from 'utils/helpers'
import { getDebtAmountWithInterest } from 'utils/tokens'
interface Props {
account: Account
}
function RepayNotAvailable(props: { asset: Asset }) {
return (
<Card className='w-full'>
<div className='flex items-start p-4'>
<InfoCircle className='w-6 mr-2 flex-0' />
<div className='flex flex-col flex-1 gap-1'>
<Text size='sm'>No funds for repay</Text>
<Text
size='xs'
className='text-white/40'
>{`Unfortunately you don't have any ${props.asset.symbol} in your Wallet to repay the debt.`}</Text>
</div>
</div>
</Card>
)
}
export default function Repay(props: Props) {
const { account } = props
const modal = useStore((s) => s.v1BorrowAndRepayModal)
const baseAsset = useBaseAsset()
const asset = modal?.data.asset ?? baseAsset
const [amount, setAmount] = useState(BN_ZERO)
const balance = useCurrentWalletBalance(asset.denom)
const v1Action = useStore((s) => s.v1Action)
const [max, setMax] = useState(BN_ZERO)
const { simulateRepay } = useUpdatedAccount(account)
const apy = modal?.data.apy.borrow ?? 0
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
const markets = useMarkets()
const accountDebtWithInterest = useMemo(
() => getDebtAmountWithInterest(accountDebt, apy),
[accountDebt, apy],
)
const overpayExeedsCap = useMemo(() => {
const marketAsset = markets.find((market) => market.asset.denom === asset.denom)
if (!marketAsset) return
const overpayAmount = accountDebtWithInterest.minus(accountDebt)
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
}, [markets, asset.denom, accountDebt, accountDebtWithInterest])
const maxRepayAmount = useMemo(() => {
const maxBalance = BN(balance?.amount ?? 0)
return BigNumber.min(maxBalance, overpayExeedsCap ? accountDebt : accountDebtWithInterest)
}, [accountDebtWithInterest, overpayExeedsCap, accountDebt, balance?.amount])
const close = useCallback(() => {
setAmount(BN_ZERO)
useStore.setState({ v1BorrowAndRepayModal: null })
}, [setAmount])
const onConfirmClick = useCallback(() => {
v1Action('repay', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
close()
}, [v1Action, asset, amount, close])
const handleChange = useCallback(
(newAmount: BigNumber) => {
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
},
[amount, setAmount],
)
const onDebounce = useCallback(() => {
const repayCoin = BNCoin.fromDenomAndBigNumber(
asset.denom,
amount.isGreaterThan(accountDebt) ? accountDebt : amount,
)
simulateRepay(repayCoin, true)
}, [amount, accountDebt, asset, simulateRepay])
useEffect(() => {
if (maxRepayAmount.isEqualTo(max)) return
setMax(maxRepayAmount)
}, [max, maxRepayAmount])
useEffect(() => {
if (amount.isLessThanOrEqualTo(max)) return
handleChange(max)
setAmount(max)
}, [amount, max, handleChange])
if (!modal) return null
return (
<Modal
onClose={close}
header={
<span className='flex items-center gap-4 px-4'>
<AssetImage asset={modal.data.asset} size={24} />
<Text>
{'Repay'} {asset.symbol}
</Text>
</span>
}
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
contentClassName='flex flex-col'
>
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
<div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'>
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={accountDebt.toNumber()}
options={{
decimals: asset.decimals,
abbreviated: false,
suffix: ` ${asset.symbol}`,
}}
/>
<DisplayCurrency
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
parentheses
/>
</div>
<Text size='xs' className='text-white/50' tag='span'>
Total Borrowed
</Text>
</div>
<div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'>
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={modal.data?.liquidity.toNumber() ?? 0}
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
animate
/>
<DisplayCurrency
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data?.liquidity ?? BN_ZERO)}
parentheses
/>
</div>
<Text size='xs' className='text-white/50' tag='span'>
Liquidity available
</Text>
</div>
</div>
<div className='flex items-start flex-1 gap-6 p-6'>
<Card
className='flex flex-1 p-4 bg-white/5'
contentClassName='gap-6 flex flex-col justify-between h-full'
>
<TokenInputWithSlider
asset={asset}
onChange={handleChange}
onDebounce={onDebounce}
amount={amount}
max={max}
disabled={max.isZero()}
className='w-full'
maxText='Max'
warningMessages={[]}
/>
<Divider />
{maxRepayAmount.isZero() && <RepayNotAvailable asset={asset} />}
<Button
onClick={onConfirmClick}
className='w-full'
disabled={amount.isZero()}
text={`Repay ${asset.symbol}`}
rightIcon={<ArrowRight />}
/>
</Card>
<AccountSummaryInModal account={account} />
</div>
</Modal>
)
}