Wormhole and sollet token selection
This commit is contained in:
parent
4a25be0fb3
commit
726a832524
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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" }}>
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue