import React, { useState } from 'react';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogForm from './DialogForm';
import { abbreviateAddress } from '../utils/utils';
import CopyableDisplay from './CopyableDisplay';
import { useSolanaExplorerUrlSuffix } from '../utils/connection';
import Typography from '@material-ui/core/Typography';
import DialogActions from '@material-ui/core/DialogActions';
import Button from '@material-ui/core/Button';
import { useAsyncData } from '../utils/fetch-loop';
import tuple from 'immutable-tuple';
import { useCallAsync } from '../utils/notifications';
import {
ConnectToMetamaskButton,
getErc20Balance,
swapErc20ToSpl,
useEthAccount,
estimateErc20SwapFees,
} from '../utils/swap/eth';
import InputAdornment from '@material-ui/core/InputAdornment';
import TextField from '@material-ui/core/TextField';
import Stepper from '@material-ui/core/Stepper';
import Step from '@material-ui/core/Step';
import StepLabel from '@material-ui/core/StepLabel';
import CircularProgress from '@material-ui/core/CircularProgress';
import Link from '@material-ui/core/Link';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import { DialogContentText, Tooltip } from '@material-ui/core';
import { EthFeeEstimate } from './EthFeeEstimate';
const DISABLED_MINTS = new Set([
'ABE7D8RU1eHfCJWzHYZZeymeE8k9nPPXfqge2NQYyKoL',
]);
export default function DepositDialog({
open,
onClose,
publicKey,
balanceInfo,
swapInfo,
isAssociatedToken,
}) {
const ethAccount = useEthAccount();
const urlSuffix = useSolanaExplorerUrlSuffix();
const { mint, tokenName, tokenSymbol, owner } = balanceInfo;
const [tab, setTab] = useState(0);
// SwapInfos to ignore.
if (
swapInfo &&
swapInfo.coin &&
swapInfo.coin.erc20Contract === '0x2b2e04bf86978b45bb2edf54aca876973bdd43c0'
) {
swapInfo = null;
}
let tabs = null;
if (swapInfo) {
let firstTab = `SPL ${tokenSymbol ?? swapInfo.coin.ticker}`;
let secondTab = swapInfo.coin.ticker;
if (!mint) {
firstTab = 'SOL';
} else {
if (localStorage.getItem('sollet-private') || swapInfo.blockchain !== 'eth') {
secondTab = `${
swapInfo.coin.erc20Contract ? 'ERC20' : 'Native'
} ${secondTab}`;
} else {
secondTab = null;
}
}
tabs = (
setTab(value)}
textColor="primary"
indicatorColor="primary"
>
{(!DISABLED_MINTS.has(mint && mint.toString()) ||
localStorage.getItem('sollet-private')) &&
secondTab && }
);
}
const displaySolAddress = publicKey.equals(owner) || isAssociatedToken;
const depositAddressStr = displaySolAddress
? owner.toBase58()
: publicKey.toBase58();
return (
Deposit {tokenName ?? mint.toBase58()}
{tokenSymbol ? ` (${tokenSymbol})` : null}
{ethAccount && (
Metamask connected: {ethAccount}
)}
{tabs}
{tab === 0 ? (
<>
{!displaySolAddress && isAssociatedToken === false ? (
This address can only be used to receive{' '}
{tokenSymbol ?? abbreviateAddress(mint)}. Do not send SOL to
this address.
WARNING: You are using a
deprecated account type. Please migrate your tokens. Ideally,
create a new wallet. If you send to this address from a poorly
implemented wallet, you may burn tokens.
) : (
This address can be used to receive{' '}
{tokenSymbol ?? abbreviateAddress(mint)}.
)}
View on Solscan
>
) : (
)}
);
}
function SolletSwapDepositAddress({ balanceInfo, swapInfo, ethAccount }) {
const [ethBalance] = useAsyncData(
() => getErc20Balance(ethAccount),
'ethBalance',
{
refreshInterval: 2000,
},
);
const ethFeeData = useAsyncData(
swapInfo.coin &&
(() =>
estimateErc20SwapFees({
erc20Address: swapInfo.coin.erc20Contract,
swapAddress: swapInfo.address,
ethAccount,
})),
'depositEthFee',
{
refreshInterval: 2000,
},
);
if (!swapInfo) {
return null;
}
const ethFeeEstimate = Array.isArray(ethFeeData[0])
? ethFeeData[0].reduce((acc, elem) => acc + elem)
: ethFeeData[0];
const insufficientEthBalance =
typeof ethBalance === 'number' &&
typeof ethFeeEstimate === 'number' &&
ethBalance < ethFeeEstimate;
const { blockchain, address, memo, coin } = swapInfo;
const { mint, tokenName } = balanceInfo;
if (blockchain === 'btc' && memo === null) {
return (
<>
Native BTC can be converted to SPL {tokenName} by sending it to the
following address:
>
);
}
if (localStorage.getItem('sollet-private') && blockchain === 'eth') {
return (
<>
{coin.erc20Contract ? 'ERC20' : 'Native'} {coin.ticker} can be
converted to {mint ? 'SPL' : 'native'} {tokenName} via MetaMask. To
convert, you must already have SOL in your wallet.
Estimated withdrawal transaction fee:
>
);
}
return null;
}
function MetamaskDeposit({ swapInfo, insufficientEthBalance }) {
const ethAccount = useEthAccount();
const [amount, setAmount] = useState('');
const [submitted, setSubmitted] = useState(false);
const [status, setStatus] = useState(null);
const callAsync = useCallAsync();
const {
address: swapAddress,
memo: destination,
coin: { erc20Contract: erc20Address, ticker },
} = swapInfo;
const [maxAmount, maxAmountLoaded] = useAsyncData(async () => {
if (ethAccount) {
return Math.min(
await getErc20Balance(ethAccount, erc20Address),
swapInfo.maxSize ?? Infinity,
);
}
return 0;
}, tuple(getErc20Balance, ethAccount, erc20Address));
if (!ethAccount) {
return ;
}
async function submit() {
setSubmitted(true);
setStatus({ step: 0 });
await callAsync(
(async () => {
let parsedAmount = parseFloat(amount);
if (!parsedAmount || parsedAmount > maxAmount || parsedAmount <= 0) {
throw new Error('Invalid amount');
}
await swapErc20ToSpl({
ethAccount,
erc20Address,
swapAddress,
destination,
amount,
onStatusChange: (e) => setStatus((status) => ({ ...status, ...e })),
});
})(),
{ onError: () => setSubmitted(false) },
);
}
if (!submitted) {
let convertButton = (
);
if (insufficientEthBalance) {
convertButton = (
{convertButton}
);
}
return (
{ticker}
),
inputProps: {
step: 'any',
},
}}
value={amount}
onChange={(e) => setAmount(e.target.value.trim())}
helperText={
maxAmountLoaded ? (
setAmount(maxAmount.toFixed(6))}>
Max: {maxAmount.toFixed(6)}
) : null
}
/>
{convertButton}
);
}
return (
<>
Approve Conversion
Send Funds
Wait for Confirmations
{status.step === 2 ? (
<>
{status.confirms ? (
{status.confirms} / 12 Confirmations
) : (
Transaction Pending
)}
View on Etherscan
>
) : null}
>
);
}