import { useState, useCallback, useMemo, useEffect } from 'react' import { PublicKey } from '@solana/web3.js' import { PencilIcon } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' import ContentBox from '../shared/ContentBox' import { useTranslation } from 'next-i18next' import SwapFormTokenList from './SwapFormTokenList' import { LinkButton } from '../shared/Button' import { EnterBottomExitBottom } from '../shared/Transitions' import { HealthType } from '@blockworks-foundation/mango-v4' import { OUTPUT_TOKEN_DEFAULT, SWAP_MARGIN_KEY } from '../../utils/constants' import HealthImpact from '@components/shared/HealthImpact' import TokenVaultWarnings from '@components/shared/TokenVaultWarnings' import SwapSettings from './SwapSettings' import InlineNotification from '@components/shared/InlineNotification' import Tooltip from '@components/shared/Tooltip' import TabUnderline from '@components/shared/TabUnderline' import MarketSwapForm from './MarketSwapForm' import LimitSwapForm from './LimitSwapForm' import Switch from '@components/forms/Switch' import useLocalStorageState from 'hooks/useLocalStorageState' import { useIsWhiteListed } from 'hooks/useIsWhiteListed' import { SwapFormTokenListType } from './SwapFormTokenList' const set = mangoStore.getState().set const SwapForm = () => { const { t } = useTranslation(['common', 'swap', 'trade']) const { data: isWhiteListed } = useIsWhiteListed() const [showTokenSelect, setShowTokenSelect] = useState() const [showSettings, setShowSettings] = useState(false) const [swapOrLimit, setSwapOrLimit] = useState('swap') const [, setSavedSwapMargin] = useLocalStorageState( SWAP_MARGIN_KEY, true, ) const { margin: useMargin, slippage, inputBank, outputBank, amountIn: amountInFormValue, amountOut: amountOutFormValue, } = mangoStore((s) => s.swap) const handleTokenInSelect = useCallback((mintAddress: string) => { const group = mangoStore.getState().group if (group) { const bank = group.getFirstBankByMint(new PublicKey(mintAddress)) set((s) => { s.swap.inputBank = bank }) } setShowTokenSelect(undefined) }, []) const handleTokenOutSelect = useCallback((mintAddress: string) => { const group = mangoStore.getState().group if (group) { const bank = group.getFirstBankByMint(new PublicKey(mintAddress)) set((s) => { s.swap.outputBank = bank }) } setShowTokenSelect(undefined) }, []) const maintProjectedHealth = useMemo(() => { const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current if ( !inputBank || !mangoAccount || !outputBank || !amountInFormValue || !amountOutFormValue || !group ) return 100 const simulatedHealthRatio = mangoAccount.simHealthRatioWithTokenPositionUiChanges( group, [ { mintPk: inputBank.mint, uiTokenAmount: parseFloat(amountInFormValue) * -1, }, { mintPk: outputBank.mint, uiTokenAmount: parseFloat(amountOutFormValue), }, ], HealthType.maint, ) return simulatedHealthRatio > 100 ? 100 : simulatedHealthRatio < 0 ? 0 : Math.trunc(simulatedHealthRatio) }, [inputBank, outputBank, amountInFormValue, amountOutFormValue]) const handleSwapOrLimit = useCallback( (orderType: string) => { setSwapOrLimit(orderType) if (orderType !== 'swap' && outputBank?.name === OUTPUT_TOKEN_DEFAULT) { const { group } = mangoStore.getState() const outputBankName = inputBank?.name === 'USDC' ? 'SOL' : 'USDC' set((state) => { state.swap.outputBank = group?.banksMapByName.get(outputBankName)?.[0] }) } }, [inputBank, outputBank, set, setSwapOrLimit], ) const handleSetMargin = () => { set((s) => { s.swap.margin = !s.swap.margin }) } useEffect(() => { setSavedSwapMargin(useMargin) }, [useMargin]) const estSlippage = useMemo(() => { const { group } = mangoStore.getState() const amountIn = parseFloat(amountInFormValue) || 0 if (!group || !inputBank || amountIn <= 0) return 0 const value = amountIn * inputBank.uiPrice const slippage = group.getPriceImpactByTokenIndex( inputBank.tokenIndex, value, ) return slippage }, [amountInFormValue, inputBank]) return (
setShowTokenSelect(undefined)} onTokenSelect={ showTokenSelect === 'input' || showTokenSelect === 'reduce-input' ? handleTokenInSelect : handleTokenOutSelect } type={showTokenSelect} useMargin={swapOrLimit === 'swap' ? useMargin : false} /> setShowSettings(false)} />
{isWhiteListed ? (
handleSwapOrLimit(v)} />
) : null} {swapOrLimit === 'swap' ? ( ) : ( )} {inputBank ? ( ) : null} {inputBank && inputBank.areBorrowsReduceOnly() && inputBank.areDepositsReduceOnly() ? (
) : null} {outputBank && outputBank.areBorrowsReduceOnly() && outputBank.areDepositsReduceOnly() ? (
) : null}
{swapOrLimit === 'swap' ? ( <>

{t('swap:margin')}

{t('swap:max-slippage')}

setShowSettings(true)} > {slippage}%
) : null} {estSlippage ? ( <>

{t('trade:est-slippage')}

{estSlippage.toFixed(2)}%
) : null}
) } export default SwapForm