Allow adding erc20 tokens via contract address
This commit is contained in:
parent
cfc57a0a37
commit
053a85da38
|
@ -30,6 +30,8 @@ import {
|
||||||
import Link from '@material-ui/core/Link';
|
import Link from '@material-ui/core/Link';
|
||||||
import CopyableDisplay from './CopyableDisplay';
|
import CopyableDisplay from './CopyableDisplay';
|
||||||
import DialogForm from './DialogForm';
|
import DialogForm from './DialogForm';
|
||||||
|
import { showSwapAddress } from '../utils/config';
|
||||||
|
import { swapApiRequest } from '../utils/swap/api';
|
||||||
|
|
||||||
const feeFormat = new Intl.NumberFormat(undefined, {
|
const feeFormat = new Intl.NumberFormat(undefined, {
|
||||||
minimumFractionDigits: 6,
|
minimumFractionDigits: 6,
|
||||||
|
@ -40,7 +42,6 @@ const useStyles = makeStyles((theme) => ({
|
||||||
tabs: {
|
tabs: {
|
||||||
marginBottom: theme.spacing(1),
|
marginBottom: theme.spacing(1),
|
||||||
borderBottom: `1px solid ${theme.palette.background.paper}`,
|
borderBottom: `1px solid ${theme.palette.background.paper}`,
|
||||||
width: '100%',
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -52,15 +53,16 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
);
|
);
|
||||||
let classes = useStyles();
|
let classes = useStyles();
|
||||||
let updateTokenName = useUpdateTokenName();
|
let updateTokenName = useUpdateTokenName();
|
||||||
|
const [sendTransaction, sending] = useSendTransaction();
|
||||||
let [mintAddress, setMintAddress] = useState('');
|
|
||||||
let [tokenName, setTokenName] = useState('');
|
|
||||||
let [tokenSymbol, setTokenSymbol] = useState('');
|
|
||||||
let [sendTransaction, sending] = useSendTransaction();
|
|
||||||
const { endpoint } = useConnectionConfig();
|
const { endpoint } = useConnectionConfig();
|
||||||
const popularTokens = TOKENS[endpoint];
|
const popularTokens = TOKENS[endpoint];
|
||||||
const [walletAccounts] = useWalletTokenAccounts();
|
const [walletAccounts] = useWalletTokenAccounts();
|
||||||
|
|
||||||
const [tab, setTab] = useState(!!popularTokens ? 'popular' : 'manual');
|
const [tab, setTab] = useState(!!popularTokens ? 'popular' : 'manual');
|
||||||
|
const [mintAddress, setMintAddress] = useState('');
|
||||||
|
const [tokenName, setTokenName] = useState('');
|
||||||
|
const [tokenSymbol, setTokenSymbol] = useState('');
|
||||||
|
const [erc20Address, setErc20Address] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!popularTokens) {
|
if (!popularTokens) {
|
||||||
|
@ -68,17 +70,46 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
}
|
}
|
||||||
}, [popularTokens]);
|
}, [popularTokens]);
|
||||||
|
|
||||||
function onSubmit({ mintAddress, tokenName, tokenSymbol }) {
|
function onSubmit(params) {
|
||||||
let mint = new PublicKey(mintAddress);
|
if (tab === 'manual') {
|
||||||
sendTransaction(wallet.createTokenAccount(mint), {
|
params = { mintAddress, tokenName, tokenSymbol };
|
||||||
|
} else if (tab === 'erc20') {
|
||||||
|
params = { erc20Address };
|
||||||
|
}
|
||||||
|
sendTransaction(addToken(params), {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
updateTokenName(mint, tokenName, tokenSymbol);
|
|
||||||
refreshWalletPublicKeys(wallet);
|
refreshWalletPublicKeys(wallet);
|
||||||
onClose();
|
onClose();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addToken({
|
||||||
|
mintAddress,
|
||||||
|
tokenName,
|
||||||
|
tokenSymbol,
|
||||||
|
erc20Address,
|
||||||
|
}) {
|
||||||
|
if (erc20Address) {
|
||||||
|
let tokenInfo = await swapApiRequest('POST', `coins/eth/${erc20Address}`);
|
||||||
|
mintAddress = tokenInfo.splMint;
|
||||||
|
tokenName = tokenInfo.name;
|
||||||
|
tokenSymbol = tokenInfo.ticker;
|
||||||
|
if (tokenInfo.blockchain !== 'sol') {
|
||||||
|
tokenName = 'Wrapped ' + tokenName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mint = new PublicKey(mintAddress);
|
||||||
|
updateTokenName(mint, tokenName, tokenSymbol);
|
||||||
|
return await wallet.createTokenAccount(mint);
|
||||||
|
}
|
||||||
|
|
||||||
|
let valid = true;
|
||||||
|
if (tab === 'erc20') {
|
||||||
|
valid = erc20Address.length === 42 && erc20Address.startsWith('0x');
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogForm open={open} onClose={onClose}>
|
<DialogForm open={open} onClose={onClose}>
|
||||||
<DialogTitle>Add Token</DialogTitle>
|
<DialogTitle>Add Token</DialogTitle>
|
||||||
|
@ -94,22 +125,14 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
{!!popularTokens && (
|
{!!popularTokens && (
|
||||||
<Tabs
|
<Tabs
|
||||||
value={tab}
|
value={tab}
|
||||||
variant="standard"
|
|
||||||
textColor="primary"
|
textColor="primary"
|
||||||
indicatorColor="primary"
|
indicatorColor="primary"
|
||||||
className={classes.tabs}
|
className={classes.tabs}
|
||||||
onChange={(e, value) => setTab(value)}
|
onChange={(e, value) => setTab(value)}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab label="Popular Tokens" value="popular" />
|
||||||
label={'Popular Tokens'}
|
{showSwapAddress ? <Tab label="ERC20 Token" value="erc20" /> : null}
|
||||||
value="popular"
|
<Tab label="Manual Input" value="manual" />
|
||||||
style={{ textDecoration: 'none', width: '50%' }}
|
|
||||||
/>
|
|
||||||
<Tab
|
|
||||||
label={'Manual Input'}
|
|
||||||
value="manual"
|
|
||||||
style={{ textDecoration: 'none', width: '50%' }}
|
|
||||||
/>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
)}
|
)}
|
||||||
{tab === 'manual' || !popularTokens ? (
|
{tab === 'manual' || !popularTokens ? (
|
||||||
|
@ -121,6 +144,8 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
margin="normal"
|
margin="normal"
|
||||||
value={mintAddress}
|
value={mintAddress}
|
||||||
onChange={(e) => setMintAddress(e.target.value)}
|
onChange={(e) => setMintAddress(e.target.value)}
|
||||||
|
autoFocus
|
||||||
|
disabled={sending}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Token Name"
|
label="Token Name"
|
||||||
|
@ -129,6 +154,7 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
margin="normal"
|
margin="normal"
|
||||||
value={tokenName}
|
value={tokenName}
|
||||||
onChange={(e) => setTokenName(e.target.value)}
|
onChange={(e) => setTokenName(e.target.value)}
|
||||||
|
disabled={sending}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Token Symbol"
|
label="Token Symbol"
|
||||||
|
@ -137,9 +163,10 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
margin="normal"
|
margin="normal"
|
||||||
value={tokenSymbol}
|
value={tokenSymbol}
|
||||||
onChange={(e) => setTokenSymbol(e.target.value)}
|
onChange={(e) => setTokenSymbol(e.target.value)}
|
||||||
|
disabled={sending}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : (
|
) : tab === 'popular' ? (
|
||||||
<List disablePadding>
|
<List disablePadding>
|
||||||
{popularTokens.map((token) => (
|
{popularTokens.map((token) => (
|
||||||
<TokenListItem
|
<TokenListItem
|
||||||
|
@ -154,15 +181,37 @@ export default function AddTokenDialog({ open, onClose }) {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
)}
|
) : tab === 'erc20' ? (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
label="ERC20 Contract Address"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
margin="normal"
|
||||||
|
value={erc20Address}
|
||||||
|
onChange={(e) => setErc20Address(e.target.value.trim())}
|
||||||
|
autoFocus
|
||||||
|
disabled={sending}
|
||||||
|
/>
|
||||||
|
{erc20Address && valid ? (
|
||||||
|
<Link
|
||||||
|
href={`https://etherscan.io/token/${erc20Address}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
View on Etherscan
|
||||||
|
</Link>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onClose}>Cancel</Button>
|
<Button onClick={onClose}>Cancel</Button>
|
||||||
{tab === 'manual' && (
|
{tab !== 'popular' && (
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={sending}
|
disabled={sending || !valid}
|
||||||
onClick={() => onSubmit({ tokenName, tokenSymbol, mintAddress })}
|
onClick={() => onSubmit({ tokenName, tokenSymbol, mintAddress })}
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
|
|
|
@ -124,6 +124,15 @@ export function useUpdateTokenName() {
|
||||||
const { endpoint } = useConnectionConfig();
|
const { endpoint } = useConnectionConfig();
|
||||||
return useCallback(
|
return useCallback(
|
||||||
function updateTokenName(mint, name, symbol) {
|
function updateTokenName(mint, name, symbol) {
|
||||||
|
if (!name || !symbol) {
|
||||||
|
if (name) {
|
||||||
|
symbol = name;
|
||||||
|
} else if (symbol) {
|
||||||
|
name = symbol;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!customTokenNamesByNetwork[endpoint]) {
|
if (!customTokenNamesByNetwork[endpoint]) {
|
||||||
customTokenNamesByNetwork[endpoint] = {};
|
customTokenNamesByNetwork[endpoint] = {};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue