import { useCallback, useEffect, useState } from 'react' import { BN_ZERO } from 'constants/math' import usePrices from 'hooks/usePrices' import { addCoins, addValueToVaults, getDepositAndLendCoinsToSpend, removeCoins, } from 'hooks/useUpdatedAccount/functions' import useVaults from 'hooks/useVaults' import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { cloneAccount } from 'utils/accounts' import { byDenom } from 'utils/array' import { getValueFromBNCoins } from 'utils/helpers' export interface VaultValue { address: string value: BigNumber } export function useUpdatedAccount(account?: Account) { const { data: availableVaults } = useVaults(false) const { data: prices } = usePrices() const [updatedAccount, setUpdatedAccount] = useState( account ? cloneAccount(account) : undefined, ) const [addedDeposits, addDeposits] = useState([]) const [removedDeposits, removeDeposits] = useState([]) const [addedDebts, addDebts] = useState([]) const [removedDebts, removeDebts] = useState([]) const [addedVaultValues, addVaultValues] = useState([]) const [addedLends, addLends] = useState([]) const [removedLends, removeLends] = useState([]) const removeDepositAndLendsByDenom = useCallback( (denom: string) => { if (!account) return const deposit = account.deposits.find(byDenom(denom)) const lend = account.lends.find(byDenom(denom)) if (deposit) { removeDeposits((prevRemovedDeposits) => { return [ ...prevRemovedDeposits.filter((removedDeposit) => removedDeposit.denom !== denom), deposit, ] }) } if (lend) { removeLends((prevRemovedLends) => { return [...prevRemovedLends.filter((removedLends) => removedLends.denom !== denom), lend] }) } }, [account, removeDeposits], ) const simulateBorrow = useCallback( (target: 'wallet' | 'deposit' | 'lend', coin: BNCoin) => { if (!account) return removeDeposits([]) removeLends([]) addDebts([coin]) if (target === 'deposit') addDeposits([coin]) if (target === 'lend') addLends([coin]) }, [account, addDebts, addDeposits, addLends], ) const simulateLending = useCallback( (isLendAction: boolean, coin: BNCoin) => { if (!account) return if (isLendAction) { addLends([coin]) removeDeposits([coin]) return } removeLends([coin]) addDeposits([coin]) }, [account, addDeposits, addLends, removeDeposits, removeLends], ) const simulateRepay = useCallback( (coin: BNCoin) => { if (!account) return const { deposit, lend } = getDepositAndLendCoinsToSpend(coin, account) removeDebts([coin]) removeDeposits([deposit]) removeLends([lend]) }, [account, removeDebts, removeDeposits, removeLends], ) const simulateDeposits = useCallback( (target: 'deposit' | 'lend', coins: BNCoin[]) => { if (!account) return addDeposits([]) addLends([]) if (target === 'deposit') addDeposits(coins) if (target === 'lend') addLends(coins) }, [account, addDeposits, addLends], ) const simulateWithdraw = useCallback( (withdrawWithBorrowing: boolean, coin: BNCoin) => { if (!account) return removeDeposits([]) removeLends([]) addDebts([]) const { deposit, lend } = getDepositAndLendCoinsToSpend(coin, account) const totalBalance = deposit.amount.plus(lend.amount) removeDeposits([deposit]) removeLends([lend]) if (withdrawWithBorrowing) { addDebts([BNCoin.fromDenomAndBigNumber(coin.denom, coin.amount.minus(totalBalance))]) } }, [account, removeDeposits, removeLends, addDebts], ) const simulateTrade = useCallback( (removeCoin: BNCoin, addCoin: BNCoin, debtCoin: BNCoin, target: 'deposit' | 'lend') => { removeDeposits([]) removeLends([]) addDebts([]) addDeposits([]) addLends([]) const { deposit, lend } = getDepositAndLendCoinsToSpend(removeCoin, account) removeDeposits([deposit]) removeLends([lend]) if (target === 'deposit') addDeposits([addCoin]) if (target === 'lend') addLends([addCoin]) if (debtCoin.amount.isGreaterThan(BN_ZERO)) addDebts([debtCoin]) }, [account, addDebts, addDeposits, addLends, removeDeposits, removeLends], ) const simulateVaultDeposit = useCallback( (address: string, coins: BNCoin[]) => { if (!account) return const value = getValueFromBNCoins(coins, prices) const totalDeposits: BNCoin[] = [] const totalLends: BNCoin[] = [] coins.forEach((coin) => { const { deposit, lend } = getDepositAndLendCoinsToSpend(coin, account) totalDeposits.push(deposit) totalLends.push(lend) }) addVaultValues([{ address, value }]) removeDeposits(totalDeposits) removeLends(totalLends) }, [account, prices], ) useEffect(() => { if (!account) return const accountCopy = cloneAccount(account) accountCopy.deposits = addCoins(addedDeposits, [...accountCopy.deposits]) accountCopy.debts = addCoins(addedDebts, [...accountCopy.debts]) accountCopy.vaults = addValueToVaults( addedVaultValues, [...accountCopy.vaults], availableVaults ?? [], ) accountCopy.deposits = removeCoins(removedDeposits, [...accountCopy.deposits]) accountCopy.debts = removeCoins(removedDebts, [...accountCopy.debts]) accountCopy.lends = addCoins(addedLends, [...accountCopy.lends]) accountCopy.lends = removeCoins(removedLends, [...accountCopy.lends]) setUpdatedAccount(accountCopy) useStore.setState({ updatedAccount: accountCopy }) return () => useStore.setState({ updatedAccount: undefined }) }, [ account, addedDebts, removedDebts, addedDeposits, removedDeposits, addedVaultValues, addedLends, removedLends, availableVaults, ]) return { updatedAccount, addDeposits, removeDeposits, removeDepositAndLendsByDenom, addDebts, removeDebts, addLends, removeLends, addVaultValues, addedDeposits, addedDebts, addedLends, removedDeposits, removedDebts, removedLends, simulateBorrow, simulateDeposits, simulateLending, simulateRepay, simulateTrade, simulateVaultDeposit, simulateWithdraw, } }