mars-v2-frontend/src/components/Modals/HLS/Manage/Deposit.tsx
Bob van der Helm ab0e184a39
refactor components folder (#734)
* refactor components folder

* create leverage slider variants
2024-01-16 15:35:18 +01:00

265 lines
8.2 KiB
TypeScript

import BigNumber from 'bignumber.js'
import React, { useCallback, useMemo } from 'react'
import Button from 'components/common/Button'
import Divider from 'components/common/Divider'
import SummaryItems from 'components/common/SummaryItems'
import Switch from 'components/common/Switch'
import Text from 'components/common/Text'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import { BN_ZERO } from 'constants/math'
import useAllAssets from 'hooks/assets/useAllAssets'
import useDepositActions from 'hooks/HLS/useDepositActions'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import useHealthComputer from 'hooks/useHealthComputer'
import usePrices from 'hooks/usePrices'
import useToggle from 'hooks/useToggle'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { calculateAccountLeverage } from 'utils/accounts'
import { byDenom } from 'utils/array'
import { getCoinAmount, getCoinValue } from 'utils/formatters'
import { BN } from 'utils/helpers'
import {
getDepositCapMessage,
getHealthFactorMessage,
getLiquidityMessage,
getNoBalanceInWalletMessage,
} from 'utils/messages'
interface Props {
account: HLSAccountWithStrategy
action: HlsStakingManageAction
borrowAsset: BorrowAsset
collateralAsset: Asset
}
export default function Deposit(props: Props) {
const { addedDeposits, addedDebts, updatedAccount, addedTrades, simulateHlsStakingDeposit } =
useUpdatedAccount(props.account)
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
const assets = useAllAssets()
const { data: prices } = usePrices()
const [keepLeverage, toggleKeepLeverage] = useToggle(true)
const collateralAssetAmountInWallet = BN(
useCurrentWalletBalance(props.collateralAsset.denom)?.amount || '0',
)
const addToStakingStrategy = useStore((s) => s.addToStakingStrategy)
const borrowRate = useBorrowAsset(props.borrowAsset.denom)?.borrowRate || 0
const currentLeverage = useMemo(
() => calculateAccountLeverage(props.account, prices, assets).toNumber(),
[prices, props.account, assets],
)
const depositCoin = useMemo(
() =>
BNCoin.fromDenomAndBigNumber(
props.collateralAsset.denom,
addedDeposits.find(byDenom(props.collateralAsset.denom))?.amount || BN_ZERO,
),
[addedDeposits, props.collateralAsset.denom],
)
const addedDepositFromSwap = useMemo(
() => addedTrades.find(byDenom(props.collateralAsset.denom))?.amount || BN_ZERO,
[addedTrades, props.collateralAsset.denom],
)
const borrowCoin = useMemo(
() =>
BNCoin.fromDenomAndBigNumber(
props.borrowAsset.denom,
addedDebts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
),
[addedDebts, props.borrowAsset.denom],
)
const warningMessages = useMemo(() => {
let messages: string[] = []
const capLeft = props.account.strategy.depositCap.max.minus(
props.account.strategy.depositCap.used,
)
if (capLeft.isLessThan(depositCoin.amount.plus(addedDepositFromSwap))) {
messages.push(getDepositCapMessage(props.collateralAsset.denom, capLeft, 'deposit', assets))
}
if (collateralAssetAmountInWallet.isZero()) {
messages.push(getNoBalanceInWalletMessage(props.collateralAsset.symbol))
}
return messages
}, [
addedDepositFromSwap,
collateralAssetAmountInWallet,
depositCoin.amount,
props.account.strategy.depositCap.max,
props.account.strategy.depositCap.used,
props.collateralAsset.denom,
props.collateralAsset.symbol,
assets,
])
const maxBorrowAmount = useMemo(
() => computeMaxBorrowAmount(props.borrowAsset.denom, 'deposit'),
[computeMaxBorrowAmount, props.borrowAsset.denom],
)
const borrowWarningMessages = useMemo(() => {
let messages: string[] = []
if (borrowCoin.amount.isGreaterThan(maxBorrowAmount)) {
messages.push(
getHealthFactorMessage(props.borrowAsset.denom, maxBorrowAmount, 'borrow', assets),
)
}
const borrowLiquidity = props.borrowAsset.liquidity?.amount || BN_ZERO
if (borrowCoin.amount.isGreaterThan(borrowLiquidity)) {
messages.push(getLiquidityMessage(props.borrowAsset.denom, borrowLiquidity, assets))
}
return messages
}, [
assets,
borrowCoin.amount,
maxBorrowAmount,
props.borrowAsset.denom,
props.borrowAsset.liquidity?.amount,
])
const actions = useDepositActions({ depositCoin, borrowCoin })
const currentDebt: BigNumber = useMemo(
() => props.account.debts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowAsset.denom],
)
const handleDeposit = useCallback(() => {
useStore.setState({ hlsManageModal: null })
addToStakingStrategy({
accountId: props.account.id,
actions,
depositCoin,
borrowCoin,
})
}, [actions, addToStakingStrategy, borrowCoin, depositCoin, props.account.id])
const handleOnChange = useCallback(
(amount: BigNumber) => {
let additionalDebt = BN_ZERO
if (currentLeverage > 1 && keepLeverage) {
const depositValue = getCoinValue(
BNCoin.fromDenomAndBigNumber(props.collateralAsset.denom, amount),
prices,
assets,
)
const borrowValue = BN(currentLeverage - 1).times(depositValue)
additionalDebt = getCoinAmount(props.borrowAsset.denom, borrowValue, prices, assets)
}
simulateHlsStakingDeposit(
BNCoin.fromDenomAndBigNumber(props.collateralAsset.denom, amount),
BNCoin.fromDenomAndBigNumber(props.borrowAsset.denom, additionalDebt),
)
},
[
currentLeverage,
keepLeverage,
prices,
props.borrowAsset.denom,
props.collateralAsset.denom,
simulateHlsStakingDeposit,
assets,
],
)
const items: SummaryItem[] = useMemo(
() => [
...(keepLeverage
? [
{
title: 'Borrow rate',
amount: borrowRate,
options: {
suffix: `%`,
minDecimals: 2,
maxDecimals: 2,
},
},
{
title: 'Additional Borrow Amount',
amount: borrowCoin.amount.toNumber(),
warningMessages: borrowWarningMessages,
options: {
suffix: ` ${props.borrowAsset.symbol}`,
abbreviated: true,
decimals: props.borrowAsset.decimals,
},
},
{
title: 'New Debt Amount',
amount: currentDebt.plus(borrowCoin.amount).toNumber(),
options: {
suffix: ` ${props.borrowAsset.symbol}`,
abbreviated: true,
decimals: props.borrowAsset.decimals,
},
},
]
: []),
],
[
borrowCoin.amount,
borrowRate,
borrowWarningMessages,
currentDebt,
keepLeverage,
props.borrowAsset.decimals,
props.borrowAsset.symbol,
],
)
return (
<>
<div>
<TokenInputWithSlider
amount={depositCoin.amount}
asset={props.collateralAsset}
max={collateralAssetAmountInWallet}
onChange={handleOnChange}
maxText='In Wallet'
warningMessages={warningMessages}
/>
<Divider className='my-6' />
<div className='flex flex-wrap items-center justify-between flex-1'>
<div>
<Text className='w-full mb-1'>Keep leverage</Text>
<Text size='xs' className='text-white/50'>
Automatically borrow more funds to keep leverage
</Text>
</div>
<Switch name='keep-leverage' checked={keepLeverage} onChange={toggleKeepLeverage} />
</div>
</div>
<div className='flex flex-col gap-4'>
<SummaryItems items={items} />
<Button
onClick={handleDeposit}
text='Deposit'
disabled={
depositCoin.amount.isZero() ||
!!warningMessages.length ||
!!borrowWarningMessages.length
}
/>
</div>
</>
)
}