import React, { FunctionComponent, useEffect, useMemo, useState } from 'react' import { ExclamationCircleIcon } from '@heroicons/react/outline' import { nativeToUi, sleep, } from '@blockworks-foundation/mango-client/lib/utils' import Input from './Input' import AccountSelect from './AccountSelect' import { ElementTitle } from './styles' import useMangoStore from '../stores/useMangoStore' import useMarketList from '../hooks/useMarketList' import { getSymbolForTokenMintAddress, DECIMALS, trimDecimals, } from '../utils/index' import useConnection from '../hooks/useConnection' import { initMarginAccountAndDeposit } from '../utils/mango' import { PublicKey } from '@solana/web3.js' import Loading from './Loading' import Button from './Button' import Slider from './Slider' import { notify } from '../utils/notifications' interface NewAccountProps { onAccountCreation?: (x?) => void } const NewAccount: FunctionComponent = ({ onAccountCreation, }) => { const [inputAmount, setInputAmount] = useState(0) const [submitting, setSubmitting] = useState(false) const [invalidAmountMessage, setInvalidAmountMessage] = useState('') const [sliderPercentage, setSliderPercentage] = useState(0) const [maxButtonTransition, setMaxButtonTransition] = useState(false) const { getTokenIndex, symbols } = useMarketList() const { connection, programId } = useConnection() const mintDecimals = useMangoStore((s) => s.selectedMangoGroup.mintDecimals) const walletAccounts = useMangoStore((s) => s.wallet.balances) const actions = useMangoStore((s) => s.actions) const depositAccounts = useMemo( () => walletAccounts.filter((acc) => Object.values(symbols).includes(acc.account.mint.toString()) ), [symbols, walletAccounts] ) const [selectedAccount, setSelectedAccount] = useState(depositAccounts[0]) const symbol = getSymbolForTokenMintAddress( selectedAccount?.account?.mint.toString() ) const handleAccountSelect = (account) => { setInputAmount(0) setSliderPercentage(0) setInvalidAmountMessage('') setSelectedAccount(account) } // TODO: remove duplication in AccountSelect const getBalanceForAccount = (account) => { const mintAddress = account?.account.mint.toString() const balance = nativeToUi( account?.account?.amount, mintDecimals[getTokenIndex(mintAddress)] ) return balance } const setMaxForSelectedAccount = () => { const max = getBalanceForAccount(selectedAccount) setInputAmount(max) setSliderPercentage(100) setInvalidAmountMessage('') setMaxButtonTransition(true) } const handleNewAccountDeposit = () => { setSubmitting(true) const mangoGroup = useMangoStore.getState().selectedMangoGroup.current const wallet = useMangoStore.getState().wallet.current initMarginAccountAndDeposit( connection, new PublicKey(programId), mangoGroup, wallet, selectedAccount.account.mint, selectedAccount.publicKey, Number(inputAmount) ) .then(async (_response: Array) => { await sleep(1000) actions.fetchWalletBalances() actions.fetchMarginAccounts() setSubmitting(false) onAccountCreation(_response[0].publicKey) }) .catch((err) => { setSubmitting(false) console.error(err) notify({ message: 'Could not perform init margin account and deposit operation', type: 'error', }) onAccountCreation() }) } const validateAmountInput = (amount) => { if (Number(amount) <= 0) { setInvalidAmountMessage('Enter an amount to deposit') } if (Number(amount) > getBalanceForAccount(selectedAccount)) { setInvalidAmountMessage( 'Insufficient balance. Reduce the amount to deposit' ) } } const onChangeAmountInput = (amount) => { const max = getBalanceForAccount(selectedAccount) setInputAmount(amount) setSliderPercentage((amount / max) * 100) setInvalidAmountMessage('') } const onChangeSlider = async (percentage) => { const max = getBalanceForAccount(selectedAccount) const amount = (percentage / 100) * max if (percentage === 100) { setInputAmount(amount) } else { setInputAmount(trimDecimals(amount, DECIMALS[symbol])) } setSliderPercentage(percentage) setInvalidAmountMessage('') validateAmountInput(amount) } // turn off slider transition for dragging slider handle interaction useEffect(() => { if (maxButtonTransition) { setMaxButtonTransition(false) } }, [maxButtonTransition]) return ( <> Create Margin Account
Make a deposit to initialize a new margin account
Amount
Max
validateAmountInput(e.target.value)} value={inputAmount} onChange={(e) => onChangeAmountInput(e.target.value)} suffix={symbol} />
{invalidAmountMessage ? (
{invalidAmountMessage}
) : null}
onChangeSlider(v)} step={1} maxButtonTransition={maxButtonTransition} />
) } export default NewAccount