feat: added borrow and repay
This commit is contained in:
parent
37be3240eb
commit
21bedd7905
@ -35,18 +35,9 @@ interface Props {
|
||||
modal: BorrowModal
|
||||
}
|
||||
|
||||
function getDebtAmount(modal: BorrowModal) {
|
||||
return BN((modal.marketData as BorrowMarketTableData)?.debt ?? 0).toString()
|
||||
}
|
||||
|
||||
function getAssetLogo(modal: BorrowModal) {
|
||||
if (!modal.asset) return null
|
||||
return <AssetImage asset={modal.asset} size={24} />
|
||||
}
|
||||
|
||||
function RepayNotAvailable(props: { asset: Asset; repayFromWallet: boolean }) {
|
||||
return (
|
||||
<Card className='mt-6'>
|
||||
<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'>
|
||||
@ -90,7 +81,6 @@ function BorrowModal(props: Props) {
|
||||
const apy = modal.marketData.apy.borrow
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||
const totalDebt = BN(getDebtAmount(modal))
|
||||
const accountDebt = account.debts.find(byDenom(asset.denom))?.amount ?? BN_ZERO
|
||||
const markets = useMarkets()
|
||||
|
||||
@ -237,7 +227,7 @@ function BorrowModal(props: Props) {
|
||||
onClose={onClose}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
{getAssetLogo(modal)}
|
||||
<AssetImage asset={asset} size={24} />
|
||||
<Text>
|
||||
{isRepay ? 'Repay' : 'Borrow'} {asset.symbol}
|
||||
</Text>
|
||||
@ -251,14 +241,14 @@ function BorrowModal(props: Props) {
|
||||
title={formatPercent(modal.marketData.apy.borrow)}
|
||||
sub={'Borrow Rate APY'}
|
||||
/>
|
||||
{totalDebt.isGreaterThan(0) && (
|
||||
{accountDebt.isGreaterThan(0) && (
|
||||
<>
|
||||
<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={totalDebt.toNumber()}
|
||||
amount={accountDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
@ -267,7 +257,7 @@ function BorrowModal(props: Props) {
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt)}
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
@ -303,59 +293,57 @@ function BorrowModal(props: Props) {
|
||||
<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 min-h-[380px]'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<div className='flex flex-wrap w-full'>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
{isRepay && maxRepayAmount.isZero() && (
|
||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||
)}
|
||||
{isRepay ? (
|
||||
<>
|
||||
<Divider className='my-6' />
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
{isRepay && maxRepayAmount.isZero() && (
|
||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||
)}
|
||||
{isRepay ? (
|
||||
<>
|
||||
<Divider />
|
||||
<div className='flex items-center w-full'>
|
||||
<div className='flex flex-wrap flex-1'>
|
||||
<Text className='w-full mb-1'>Repay from Wallet</Text>
|
||||
<Text size='xs' className='text-white/50'>
|
||||
Repay your debt directly from your wallet
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex flex-wrap items-center justify-end'>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={repayFromWallet}
|
||||
onChange={setRepayFromWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider className='my-6' />
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={repayFromWallet}
|
||||
onChange={setRepayFromWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider />
|
||||
<div className='flex items-center w-full'>
|
||||
<div className='flex flex-wrap flex-1'>
|
||||
<Text className='w-full mb-1'>Receive funds to Wallet</Text>
|
||||
<Text size='xs' className='text-white/50'>
|
||||
Your borrowed funds will directly go to your wallet
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex flex-wrap items-center justify-end'>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={borrowToWallet}
|
||||
onChange={setBorrowToWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={borrowToWallet}
|
||||
onChange={setBorrowToWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
LendAndReclaimModalController,
|
||||
SettingsModal,
|
||||
UnlockModal,
|
||||
V1BorrowAndRepay,
|
||||
V1DepositAndWithdraw,
|
||||
VaultModal,
|
||||
WalletAssets,
|
||||
@ -34,6 +35,7 @@ export default function ModalsContainer() {
|
||||
<HlsModal />
|
||||
<HlsManageModal />
|
||||
<V1DepositAndWithdraw />
|
||||
<V1BorrowAndRepay />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
|
||||
export { default as LendAndReclaimModalController } from 'components/Modals/LendAndReclaim'
|
||||
export { default as SettingsModal } from 'components/Modals/Settings'
|
||||
export { default as UnlockModal } from 'components/Modals/Unlock'
|
||||
export { default as V1DepositAndWithdraw } from 'components/Modals/V1DepositAndWithdraw'
|
||||
export { default as VaultModal } from 'components/Modals/Vault'
|
||||
export { default as WalletAssets } from 'components/Modals/WalletAssets'
|
||||
export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal'
|
||||
export { default as V1BorrowAndRepay } from 'components/Modals/v1/V1BorrowAndRepay'
|
||||
export { default as V1DepositAndWithdraw } from 'components/Modals/v1/V1DepositAndWithdraw'
|
||||
|
179
src/components/Modals/v1/Borrow.tsx
Normal file
179
src/components/Modals/v1/Borrow.tsx
Normal file
@ -0,0 +1,179 @@
|
||||
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 } 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 useHealthComputer from 'hooks/useHealthComputer'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Borrow(props: Props) {
|
||||
const { account } = props
|
||||
const modal = useStore((s) => s.v1BorrowAndRepayModal)
|
||||
const baseAsset = useBaseAsset()
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [max, setMax] = useState(BN_ZERO)
|
||||
const { simulateBorrow } = useUpdatedAccount(account)
|
||||
const apy = modal?.data.apy.borrow ?? 0
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
|
||||
|
||||
const accountDebtWithInterest = useMemo(
|
||||
() => getDebtAmountWithInterest(accountDebt, apy),
|
||||
[accountDebt, apy],
|
||||
)
|
||||
|
||||
const close = useCallback(() => {
|
||||
setAmount(BN_ZERO)
|
||||
useStore.setState({ v1BorrowAndRepayModal: null })
|
||||
}, [setAmount])
|
||||
|
||||
const onConfirmClick = useCallback(() => {
|
||||
v1Action('borrow', 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 borrowCoin = BNCoin.fromDenomAndBigNumber(
|
||||
asset.denom,
|
||||
amount.isGreaterThan(max) ? max : amount,
|
||||
)
|
||||
simulateBorrow('wallet', borrowCoin)
|
||||
}, [amount, max, asset, simulateBorrow])
|
||||
|
||||
const maxBorrow = useMemo(() => {
|
||||
const maxBorrowAmount = computeMaxBorrowAmount(asset.denom, 'wallet')
|
||||
|
||||
return BigNumber.min(maxBorrowAmount, modal?.data.liquidity || 0)
|
||||
}, [asset.denom, computeMaxBorrowAmount, modal?.data.liquidity])
|
||||
|
||||
useEffect(() => {
|
||||
if (maxBorrow.isEqualTo(max)) return
|
||||
setMax(maxBorrow)
|
||||
}, [account, maxBorrow, max])
|
||||
|
||||
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>{`Borrow ${asset.symbol} from the Red Bank`}</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'} />
|
||||
{accountDebt.isGreaterThan(0) && (
|
||||
<>
|
||||
<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 />
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
disabled={amount.isZero()}
|
||||
text={`Borrow ${asset.symbol}`}
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -11,9 +11,8 @@ import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
import AssetAmountSelectActionModal from '../AssetAmountSelectActionModal'
|
||||
import DetailsHeader from '../LendAndReclaim/DetailsHeader'
|
||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
208
src/components/Modals/v1/Repay.tsx
Normal file
208
src/components/Modals/v1/Repay.tsx
Normal file
@ -0,0 +1,208 @@
|
||||
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>
|
||||
)
|
||||
}
|
15
src/components/Modals/v1/V1BorrowAndRepay.tsx
Normal file
15
src/components/Modals/v1/V1BorrowAndRepay.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
import Borrow from 'components/Modals/v1/Borrow'
|
||||
import Repay from 'components/Modals/v1/Repay'
|
||||
|
||||
export default function V1BorrowAndRepayModal() {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
const modal = useStore<V1BorrowAndRepayModal | null>((s) => s.v1BorrowAndRepayModal)
|
||||
const isBorrow = modal?.type === 'borrow'
|
||||
|
||||
if (!modal || !account) return null
|
||||
if (isBorrow) return <Borrow account={account} />
|
||||
return <Repay account={account} />
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
|
||||
import Deposit from './Deposit'
|
||||
import Withdraw from './Withdraw'
|
||||
import Deposit from 'components/Modals/v1/Deposit'
|
||||
import Withdraw from 'components/Modals/v1/Withdraw'
|
||||
|
||||
export default function V1DepositAndWithdraw() {
|
||||
const address = useStore((s) => s.address)
|
@ -1,5 +1,7 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
@ -7,9 +9,6 @@ import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
import AssetAmountSelectActionModal from '../AssetAmountSelectActionModal'
|
||||
import DetailsHeader from '../LendAndReclaim/DetailsHeader'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
@ -16,7 +16,6 @@ export const BORROW_BUTTON_META = {
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
v1?: boolean
|
||||
}
|
||||
export default function BorrowButton(props: Props) {
|
||||
const account = useCurrentAccount()
|
||||
|
@ -12,7 +12,6 @@ export const MANAGE_META = {
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
|
@ -1,17 +1,16 @@
|
||||
import moment from 'moment/moment'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons'
|
||||
import Loading from 'components/common/Loading'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useStore from 'store'
|
||||
import { VaultStatus } from 'types/enums/vault'
|
||||
|
||||
import { DEFAULT_SETTINGS } from '../../../../../constants/defaultSettings'
|
||||
import { LocalStorageKeys } from '../../../../../constants/localStorageKeys'
|
||||
import useLocalStorage from '../../../../../hooks/localStorage/useLocalStorage'
|
||||
import useAccountId from '../../../../../hooks/useAccountId'
|
||||
import useStore from '../../../../../store'
|
||||
import DropDownButton from '../../../../common/Button/DropDownButton'
|
||||
|
||||
export const MANAGE_META = { accessorKey: 'details', enableSorting: false, header: '' }
|
||||
|
||||
interface Props {
|
||||
@ -104,7 +103,7 @@ export default function Manage(props: Props) {
|
||||
if (!address) return null
|
||||
|
||||
return (
|
||||
<div className='flex justify-end z-10'>
|
||||
<div className='z-10 flex justify-end'>
|
||||
<DropDownButton
|
||||
items={ITEMS}
|
||||
text='Manage'
|
||||
|
@ -1,5 +1,5 @@
|
||||
import BorrowButton from 'components/borrow/Table/Columns/BorrowButton'
|
||||
import Manage from 'components/borrow/Table/Columns/Manage'
|
||||
import BorrowButton from 'components/v1/Table/borrowings/Columns/BorrowButton'
|
||||
import Manage from 'components/v1/Table/borrowings/Columns/Manage'
|
||||
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
@ -14,7 +14,7 @@ interface Props {
|
||||
export default function Action(props: Props) {
|
||||
const hasDebt = !props.data.accountDebtAmount?.isZero() ?? false
|
||||
|
||||
if (hasDebt) return <Manage data={props.data} v1 />
|
||||
if (hasDebt) return <Manage data={props.data} />
|
||||
|
||||
return <BorrowButton data={props.data} v1 />
|
||||
return <BorrowButton data={props.data} />
|
||||
}
|
||||
|
50
src/components/v1/Table/borrowings/Columns/BorrowButton.tsx
Normal file
50
src/components/v1/Table/borrowings/Columns/BorrowButton.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { Plus } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
export default function BorrowButton(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
|
||||
const hasCollateral = account?.lends?.length ?? 0 > 0
|
||||
|
||||
return (
|
||||
<div className='flex justify-end'>
|
||||
<ConditionalWrapper
|
||||
condition={!hasCollateral}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={
|
||||
<Text size='sm'>{`You don’t have assets deposited in the Red Bank. Please deposit assets before you borrow.`}</Text>
|
||||
}
|
||||
contentClassName='max-w-[200px]'
|
||||
className='ml-auto'
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<ActionButton
|
||||
leftIcon={<Plus />}
|
||||
disabled={!hasCollateral}
|
||||
color='tertiary'
|
||||
onClick={(e) => {
|
||||
useStore.setState({
|
||||
v1BorrowAndRepayModal: { type: 'borrow', data: props.data },
|
||||
})
|
||||
e.stopPropagation()
|
||||
}}
|
||||
text='Borrow'
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
47
src/components/v1/Table/borrowings/Columns/Manage.tsx
Normal file
47
src/components/v1/Table/borrowings/Columns/Manage.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { HandCoins, Plus } from 'components/common/Icons'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: balances } = useWalletBalances(address)
|
||||
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
|
||||
|
||||
const ITEMS: DropDownItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <Plus />,
|
||||
text: 'Borrow more',
|
||||
onClick: () =>
|
||||
useStore.setState({
|
||||
v1BorrowAndRepayModal: { type: 'borrow', data: props.data },
|
||||
}),
|
||||
},
|
||||
{
|
||||
icon: <HandCoins />,
|
||||
text: 'Repay',
|
||||
onClick: () =>
|
||||
useStore.setState({
|
||||
v1BorrowAndRepayModal: { type: 'repay', data: props.data },
|
||||
}),
|
||||
disabled: !hasBalance,
|
||||
disabledTooltip: `You don’t have any ${props.data.asset.symbol} in your Wallet.`,
|
||||
},
|
||||
],
|
||||
[hasBalance, props.data],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='z-10 flex justify-end'>
|
||||
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
||||
</div>
|
||||
)
|
||||
}
|
@ -12,7 +12,6 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
const { openLend, openReclaim } = useLendAndReclaimModal()
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: balances } = useWalletBalances(address)
|
||||
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
|
||||
|
@ -20,5 +20,6 @@ export default function createModalSlice(set: SetState<ModalSlice>, get: GetStat
|
||||
walletAssetsModal: null,
|
||||
withdrawFromVaultsModal: null,
|
||||
v1DepositAndWithdrawModal: null,
|
||||
v1BorrowAndRepayModal: null,
|
||||
}
|
||||
}
|
||||
|
8
src/types/interfaces/store/modals.d.ts
vendored
8
src/types/interfaces/store/modals.d.ts
vendored
@ -7,7 +7,6 @@ interface ModalSlice {
|
||||
hlsManageModal: HlsManageModal | null
|
||||
borrowModal: BorrowModal | null
|
||||
fundAndWithdrawModal: 'fund' | 'withdraw' | null
|
||||
v1DepositAndWithdrawModal: V1DepositAndWithdrawModal | null
|
||||
getStartedModal: boolean
|
||||
hlsInformationModal: boolean | null
|
||||
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
||||
@ -16,6 +15,8 @@ interface ModalSlice {
|
||||
vaultModal: VaultModal | null
|
||||
walletAssetsModal: WalletAssetModal | null
|
||||
withdrawFromVaultsModal: DepositedVault[] | null
|
||||
v1DepositAndWithdrawModal: V1DepositAndWithdrawModal | null
|
||||
v1BorrowAndRepayModal: V1BorrowAndRepayModal | null
|
||||
}
|
||||
|
||||
interface AlertDialogButton {
|
||||
@ -90,3 +91,8 @@ interface V1DepositAndWithdrawModal {
|
||||
type: 'deposit' | 'withdraw'
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
|
||||
interface V1BorrowAndRepayModal {
|
||||
type: 'borrow' | 'repay'
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user