import { SwapOutlined } from '@ant-design/icons' import { useWeb3React } from '@web3-react/core' import { Button, Col, Input, Row, Tooltip } from 'antd' import { RefSelectProps } from 'antd/lib/select' import BigNumber from 'bignumber.js' import React, { ReactElement, useEffect, useRef, useState } from 'react' import { Chain, ChainKey, TokenAmount, TokenWithAmounts } from '../../types' import ChainSelect from '../ChainSelect' import TokenSelect from '../TokenSelect' import { getInjectedConnector } from '../web3/connectors' interface SwapFormProps { depositChain?: ChainKey setDepositChain: Function depositToken?: string setDepositToken: Function depositAmount: BigNumber setDepositAmount: Function withdrawChain?: ChainKey setWithdrawChain: Function withdrawToken?: string setWithdrawToken: Function withdrawAmount: BigNumber setWithdrawAmount: Function estimatedWithdrawAmount: string estimatedMinWithdrawAmount?: string availableChains: Array tokens: { [ChainKey: string]: Array } balances: { [ChainKey: string]: Array } | undefined allowSameChains?: boolean forceSameToken?: boolean fixedWithdraw?: boolean alternativeToSection?: ReactElement fromSectionDesignator?: string toSectionDesignator?: string } const SwapForm = ({ depositChain, setDepositChain, depositToken, setDepositToken, depositAmount, setDepositAmount, withdrawChain, setWithdrawChain, withdrawToken, setWithdrawToken, withdrawAmount, setWithdrawAmount, estimatedWithdrawAmount, estimatedMinWithdrawAmount, availableChains, tokens, balances, allowSameChains, forceSameToken, fixedWithdraw, alternativeToSection, fromSectionDesignator, toSectionDesignator, }: SwapFormProps) => { const depositSelectRef = useRef() const withdrawSelectRef = useRef() const [depositAmountString, setDepositAmountString] = useState('') // Wallet const { activate } = useWeb3React() const connectWallet = async () => { activate(await getInjectedConnector()) } const onChangeDepositChain = (chainKey: ChainKey) => { if (!allowSameChains && withdrawChain === chainKey) { setWithdrawChain(depositChain) setWithdrawToken(depositToken) } setDepositChain(chainKey) // find same deposit token if (depositChain) { const symbol = tokens[depositChain]?.find((token) => token.address === depositToken)?.symbol const tokenAddress = tokens[chainKey]?.find((token) => token.symbol === symbol)?.address setDepositToken(tokenAddress) } } const onChangeWithdrawChain = (chainKey: ChainKey) => { if (!allowSameChains && depositChain === chainKey) { setDepositChain(withdrawChain) setDepositToken(withdrawToken) } setWithdrawChain(chainKey) // find same withdraw token if (withdrawChain) { const symbol = tokens[withdrawChain].find((token) => token.address === withdrawToken)?.symbol const tokenAddress = tokens[chainKey].find((token) => token.symbol === symbol)?.address setWithdrawToken(tokenAddress) } } const getBalance = (chainKey: ChainKey, tokenAddress: string) => { if (!balances || !balances[chainKey]) { return new BigNumber(0) } const tokenBalance = balances[chainKey].find((portfolio) => portfolio.address === tokenAddress) return tokenBalance?.amount || new BigNumber(0) } const onChangeDepositToken = (tokenAddress: string) => { // unselect depositSelectRef?.current?.blur() if (!depositChain) return // connect if (tokenAddress === 'connect') { connectWallet() return } // set token setDepositToken(tokenAddress) const balance = new BigNumber(getBalance(depositChain, tokenAddress)) if (balance.lt(depositAmount) && balance.gt(0)) { setDepositAmount(balance) } // set withdraw token? if (forceSameToken && withdrawChain) { const symbol = tokens[depositChain].find((token) => token.address === tokenAddress)?.symbol const withdrawToken = tokens[withdrawChain].find((token) => token.symbol === symbol)?.address setWithdrawToken(withdrawToken) } } const onChangeWithdrawToken = (tokenId: string) => { // unselect withdrawSelectRef?.current?.blur() // connect if (tokenId === 'connect') { connectWallet() return } // set token setWithdrawToken(tokenId) // set withdraw token? if (forceSameToken && depositChain && withdrawChain) { const symbol = tokens[withdrawChain].find((token) => token.address === tokenId)?.symbol const depositToken = tokens[depositChain].find((token) => token.symbol === symbol)?.address setDepositToken(depositToken) } } // sync depositAmountString if depositAmount changes useEffect(() => { if (!new BigNumber(depositAmountString).eq(depositAmount) && depositAmount.gte(0)) { setDepositAmountString(depositAmount.toFixed()) } }, [depositAmount, depositAmountString]) const onChangeDepositAmount = (amount: string) => { setDepositAmountString(amount) setDepositAmount(new BigNumber(amount)) setWithdrawAmount(new BigNumber(Infinity)) } const onChangeWithdrawAmount = (amount: BigNumber) => { setDepositAmount(new BigNumber(Infinity)) setWithdrawAmount(amount) } const formatAmountInput = (e: React.ChangeEvent) => { return new BigNumber(e.currentTarget.value) } const setMaxDeposit = () => { if (depositToken && depositChain) { const selectedToken = tokens[depositChain].find((token) => token.address === depositToken) if (selectedToken && selectedToken.amount) { setDepositAmount(selectedToken.amount) } } } const changeDirection = () => { setWithdrawChain(depositChain) setDepositChain(withdrawChain) setWithdrawToken(depositToken) setDepositToken(withdrawToken) } const hasSufficientBalance = () => { if (!depositToken || !depositChain) { return true } return depositAmount.lte(getBalance(depositChain, depositToken)) } return ( <>
{fromSectionDesignator ? fromSectionDesignator : 'From:'}
onChangeDepositAmount(event.currentTarget.value)} placeholder="0.0" bordered={false} className={!hasSufficientBalance() ? 'insufficient' : ''} />
{/* Swap from <-> to button */} {!alternativeToSection ? ( changeDirection()} /> ) : ( '' )} {/* "To" section*/} {!alternativeToSection ? ( <>
{toSectionDesignator ? toSectionDesignator : 'To:'}
onChangeWithdrawAmount(formatAmountInput(event))} placeholder="..." bordered={false} disabled /> {!!estimatedMinWithdrawAmount && ( ? )}
) : ( alternativeToSection )} ) } export default SwapForm