feat: added borrow and repay

This commit is contained in:
Linkie Link 2024-02-15 21:51:00 +01:00
parent 37be3240eb
commit 21bedd7905
No known key found for this signature in database
GPG Key ID: 5318B0F2564D38EA
18 changed files with 572 additions and 82 deletions

View File

@ -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'

View File

@ -10,6 +10,7 @@ import {
LendAndReclaimModalController,
SettingsModal,
UnlockModal,
V1BorrowAndRepay,
V1DepositAndWithdraw,
VaultModal,
WalletAssets,
@ -34,6 +35,7 @@ export default function ModalsContainer() {
<HlsModal />
<HlsManageModal />
<V1DepositAndWithdraw />
<V1BorrowAndRepay />
</>
)
}

View File

@ -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'

View 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>
)
}

View File

@ -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

View 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>
)
}

View 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} />
}

View File

@ -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)

View File

@ -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
}

View File

@ -16,7 +16,6 @@ export const BORROW_BUTTON_META = {
interface Props {
data: LendingMarketTableData
v1?: boolean
}
export default function BorrowButton(props: Props) {
const account = useCurrentAccount()

View File

@ -12,7 +12,6 @@ export const MANAGE_META = {
interface Props {
data: BorrowMarketTableData
v1?: boolean
}
export default function Manage(props: Props) {

View File

@ -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'

View File

@ -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} />
}

View 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 dont 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>
)
}

View 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 dont 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>
)
}

View File

@ -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))

View File

@ -20,5 +20,6 @@ export default function createModalSlice(set: SetState<ModalSlice>, get: GetStat
walletAssetsModal: null,
withdrawFromVaultsModal: null,
v1DepositAndWithdrawModal: null,
v1BorrowAndRepayModal: null,
}
}

View File

@ -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
}