Wormhole and sollet token selection

This commit is contained in:
armaniferrante 2021-05-15 21:20:11 -07:00
parent 4a25be0fb3
commit 726a832524
No known key found for this signature in database
GPG Key ID: 58BEF301E91F7828
3 changed files with 135 additions and 52 deletions

View File

@ -219,7 +219,7 @@ function TokenButton({
onClick: () => void;
}) {
return (
<Button onClick={onClick} style={{ width: "116px" }}>
<Button onClick={onClick} style={{ minWidth: "116px" }}>
<TokenIcon mint={mint} style={{ width: "25px", borderRadius: "13px" }} />
<TokenName mint={mint} />
<ExpandMore />
@ -239,7 +239,7 @@ export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
}}
>
{tokenInfo?.logoURI ? (
<img alt="token logo" style={style} src={tokenInfo?.logoURI} />
<img alt="Logo" style={style} src={tokenInfo?.logoURI} />
) : (
<div style={style}></div>
)}

View File

@ -1,19 +1,21 @@
import { useState, useMemo } from "react";
import { useState } from "react";
import { PublicKey } from "@solana/web3.js";
import { TokenInfo } from "@solana/spl-token-registry";
import {
makeStyles,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TextField,
List,
ListItem,
Typography,
Tabs,
Tab,
} from "@material-ui/core";
import { TokenIcon } from "./Swap";
import { useDexContext } from "./context/Dex";
import { useTokenMap } from "./context/TokenList";
import { USDC_MINT, USDT_MINT } from "../utils/pubkeys";
import { useSwappableTokens } from "./context/TokenList";
const useStyles = makeStyles(() => ({
dialogContent: {
@ -25,6 +27,9 @@ const useStyles = makeStyles(() => ({
borderRadius: "10px",
marginBottom: "8px",
},
tab: {
minWidth: "134px",
},
}));
export default function TokenDialog({
@ -36,78 +41,97 @@ export default function TokenDialog({
onClose: () => void;
setMint: (mint: PublicKey) => void;
}) {
const [tabSelection, setTabSelection] = useState(0);
const [tokenFilter, setTokenFilter] = useState("");
const filter = tokenFilter.toLowerCase();
const styles = useStyles();
const { swapClient } = useDexContext();
const tokens = useMemo(() => {
return swapClient
.tokens()
.concat([USDC_MINT, USDT_MINT])
.filter(
(t) => t.toString() !== "So11111111111111111111111111111111111111112"
);
}, [swapClient]);
const { swappableTokens, swappableTokensSollet, swappableTokensWormhole } =
useSwappableTokens();
const selectedTokens =
tabSelection === 0
? swappableTokens
: tabSelection === 1
? swappableTokensWormhole
: swappableTokensSollet;
let tokens =
tokenFilter === ""
? selectedTokens
: selectedTokens.filter(
(t) =>
t.symbol.toLowerCase().startsWith(filter) ||
t.name.toLowerCase().startsWith(filter) ||
t.address.toLowerCase().startsWith(filter)
);
return (
<Dialog
open={open}
onClose={onClose}
scroll={"paper"}
PaperProps={{
style: {
borderRadius: "10px",
width: "420px",
},
}}
>
<div style={{ width: "420px" }}>
<DialogTitle style={{ fontWeight: "bold" }}>Select a token</DialogTitle>
<DialogContent className={styles.dialogContent}>
<TextField
className={styles.textField}
placeholder={"Search name"}
value={tokenFilter}
onChange={(e) => setTokenFilter(e.target.value)}
InputProps={{
disableUnderline: true,
style: { padding: "10px" },
}}
/>
<div>
<List disablePadding>
{tokens.map((mint) => (
<TokenListItem
key={mint.toString()}
mint={mint}
onClick={(mint) => {
setMint(mint);
onClose();
}}
/>
))}
</List>
</div>
</DialogContent>
</div>
<DialogTitle style={{ fontWeight: "bold" }}>
<Typography variant="h6" style={{ paddingBottom: "16px" }}>
Select a token
</Typography>
<TextField
className={styles.textField}
placeholder={"Search name"}
value={tokenFilter}
onChange={(e) => setTokenFilter(e.target.value)}
InputProps={{
disableUnderline: true,
style: { padding: "10px" },
}}
/>
</DialogTitle>
<DialogContent className={styles.dialogContent} dividers={true}>
<List disablePadding>
{tokens.map((tokenInfo: TokenInfo) => (
<TokenListItem
key={tokenInfo.address}
tokenInfo={tokenInfo}
onClick={(mint) => {
setMint(mint);
onClose();
setTokenFilter("");
}}
/>
))}
</List>
</DialogContent>
<DialogActions>
<Tabs value={tabSelection} onChange={(e, v) => setTabSelection(v)}>
<Tab value={0} className={styles.tab} label="Main" />
<Tab value={1} className={styles.tab} label="Wormhole" />
<Tab value={2} className={styles.tab} label="Sollet" />
</Tabs>
</DialogActions>
</Dialog>
);
}
function TokenListItem({
mint,
tokenInfo,
onClick,
}: {
mint: PublicKey;
tokenInfo: TokenInfo;
onClick: (mint: PublicKey) => void;
}) {
const mint = new PublicKey(tokenInfo.address);
return (
<ListItem button onClick={() => onClick(mint)}>
<TokenIcon mint={mint} style={{ width: "30px", borderRadius: "15px" }} />
<TokenName mint={mint} />
<TokenName tokenInfo={tokenInfo} />
</ListItem>
);
}
function TokenName({ mint }: { mint: PublicKey }) {
const tokenMap = useTokenMap();
let tokenInfo = tokenMap.get(mint.toString());
function TokenName({ tokenInfo }: { tokenInfo: TokenInfo }) {
return (
<div style={{ marginLeft: "16px" }}>
<Typography style={{ fontWeight: "bold" }}>

View File

@ -1,13 +1,20 @@
import React, { useContext, useMemo } from "react";
import { TokenInfo } from "@solana/spl-token-registry";
import { USDC_MINT, USDT_MINT } from "../../utils/pubkeys";
type TokenListContext = {
tokenMap: Map<string, TokenInfo>;
swappableTokens: TokenInfo[];
swappableTokensSollet: TokenInfo[];
swappableTokensWormhole: TokenInfo[];
};
const _TokenListContext = React.createContext<null | TokenListContext>(null);
export function TokenListContextProvider(props: any) {
const tokenList = useMemo(() => props.tokenList.getList(), [props.tokenList]);
const tokenList = useMemo(
() => props.tokenList.filterByClusterSlug("mainnet-beta").getList(),
[props.tokenList]
);
const tokenMap = useMemo(() => {
const tokenMap = new Map();
tokenList.forEach((t: TokenInfo) => {
@ -15,8 +22,54 @@ export function TokenListContextProvider(props: any) {
});
return tokenMap;
}, [tokenList]);
const swappableTokens = useMemo(() => {
const tokens = tokenList
.filter((t: TokenInfo) => {
const isUsdxQuoted =
t.extensions?.serumV3Usdt || t.extensions?.serumV3Usdc;
const isSol =
t.address === "So11111111111111111111111111111111111111112";
return isUsdxQuoted && !isSol;
})
.concat([
tokenMap.get(USDC_MINT.toString()),
tokenMap.get(USDT_MINT.toString()),
]);
tokens.sort((a: TokenInfo, b: TokenInfo) =>
a.symbol < b.symbol ? -1 : a.symbol > b.symbol ? 1 : 0
);
return tokens;
}, [tokenList, tokenMap]);
const swappableTokensSollet = useMemo(() => {
const tokens = tokenList.filter((t: TokenInfo) => {
const isSollet = t.tags?.includes("wrapped-sollet");
return isSollet;
});
tokens.sort((a: TokenInfo, b: TokenInfo) =>
a.symbol < b.symbol ? -1 : a.symbol > b.symbol ? 1 : 0
);
return tokens;
}, [tokenList]);
const swappableTokensWormhole = useMemo(() => {
const tokens = tokenList.filter((t: TokenInfo) => {
const isSollet = t.tags?.includes("wormhole");
return isSollet;
});
tokens.sort((a: TokenInfo, b: TokenInfo) =>
a.symbol < b.symbol ? -1 : a.symbol > b.symbol ? 1 : 0
);
return tokens;
}, [tokenList]);
return (
<_TokenListContext.Provider value={{ tokenMap }}>
<_TokenListContext.Provider
value={{
tokenMap,
swappableTokens,
swappableTokensWormhole,
swappableTokensSollet,
}}
>
{props.children}
</_TokenListContext.Provider>
);
@ -34,3 +87,9 @@ export function useTokenMap(): Map<string, TokenInfo> {
const { tokenMap } = useTokenListContext();
return tokenMap;
}
export function useSwappableTokens() {
const { swappableTokens, swappableTokensWormhole, swappableTokensSollet } =
useTokenListContext();
return { swappableTokens, swappableTokensWormhole, swappableTokensSollet };
}