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