Use memoized token map
This commit is contained in:
parent
65467d00ea
commit
ef97779a84
32
src/App.tsx
32
src/App.tsx
|
@ -24,25 +24,9 @@ import "./App.css";
|
||||||
// to the `Swap` component, and then everything else is taken care of.
|
// to the `Swap` component, and then everything else is taken care of.
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: "450px",
|
|
||||||
marginLeft: "auto",
|
|
||||||
marginRight: "auto",
|
|
||||||
position: "absolute",
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SnackbarProvider maxSnack={5} autoHideDuration={8000}>
|
<SnackbarProvider maxSnack={5} autoHideDuration={8000}>
|
||||||
<AppInner />
|
<AppInner />
|
||||||
</SnackbarProvider>
|
</SnackbarProvider>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +90,21 @@ function AppInner() {
|
||||||
}, [wallet, enqueueSnackbar]);
|
}, [wallet, enqueueSnackbar]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div
|
||||||
|
style={{
|
||||||
|
width: "450px",
|
||||||
|
marginLeft: "auto",
|
||||||
|
marginRight: "auto",
|
||||||
|
position: "absolute",
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onClick={() => (!isConnected ? wallet.connect() : wallet.disconnect())}
|
onClick={() => (!isConnected ? wallet.connect() : wallet.disconnect())}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
import { Info } from "@material-ui/icons";
|
import { Info } from "@material-ui/icons";
|
||||||
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
|
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { useTokenList } from "./context/TokenList";
|
import { useTokenMap } from "./context/TokenList";
|
||||||
import { useSwapContext, useSwapFair } from "./context/Swap";
|
import { useSwapContext, useSwapFair } from "./context/Swap";
|
||||||
import { useMint } from "./context/Mint";
|
import { useMint } from "./context/Mint";
|
||||||
import { useDexContext, useMarketName, useFair } from "./context/Dex";
|
import { useDexContext, useMarketName, useFair } from "./context/Dex";
|
||||||
|
@ -41,18 +41,16 @@ export function InfoLabel() {
|
||||||
const fromMintInfo = useMint(fromMint);
|
const fromMintInfo = useMint(fromMint);
|
||||||
const fair = useSwapFair();
|
const fair = useSwapFair();
|
||||||
|
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
let fromTokenInfo = tokenList.filter(
|
let fromTokenInfo = tokenMap.get(fromMint.toString());
|
||||||
(t) => t.address === fromMint.toString()
|
let toTokenInfo = tokenMap.get(toMint.toString());
|
||||||
)[0];
|
|
||||||
let toTokenInfo = tokenList.filter((t) => t.address === toMint.toString())[0];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.infoLabel}>
|
<div className={styles.infoLabel}>
|
||||||
<Typography color="textSecondary"></Typography>
|
<Typography color="textSecondary"></Typography>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<div className={styles.fairPriceLabel}>
|
<div className={styles.fairPriceLabel}>
|
||||||
{fair !== undefined
|
{fair !== undefined && toTokenInfo && fromTokenInfo
|
||||||
? `1 ${toTokenInfo.symbol} = ${fair.toFixed(
|
? `1 ${toTokenInfo.symbol} = ${fair.toFixed(
|
||||||
fromMintInfo?.decimals
|
fromMintInfo?.decimals
|
||||||
)} ${fromTokenInfo.symbol}`
|
)} ${fromTokenInfo.symbol}`
|
||||||
|
@ -103,13 +101,9 @@ function InfoButton() {
|
||||||
function InfoDetails() {
|
function InfoDetails() {
|
||||||
const { fromMint, toMint } = useSwapContext();
|
const { fromMint, toMint } = useSwapContext();
|
||||||
const { swapClient } = useDexContext();
|
const { swapClient } = useDexContext();
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
const fromMintTicker = tokenList
|
const fromMintTicker = tokenMap.get(fromMint.toString())?.symbol;
|
||||||
.filter((t) => t.address === fromMint.toString())
|
const toMintTicker = tokenMap.get(toMint.toString())?.symbol;
|
||||||
.map((t) => t.symbol)[0];
|
|
||||||
const toMintTicker = tokenList
|
|
||||||
.filter((t) => t.address === toMint.toString())
|
|
||||||
.map((t) => t.symbol)[0];
|
|
||||||
const addresses = [
|
const addresses = [
|
||||||
{ ticker: fromMintTicker, mint: fromMint },
|
{ ticker: fromMintTicker, mint: fromMint },
|
||||||
{ ticker: toMintTicker, mint: toMint },
|
{ ticker: toMintTicker, mint: toMint },
|
||||||
|
|
|
@ -32,7 +32,7 @@ import { SettingsOutlined as Settings, Close } from "@material-ui/icons";
|
||||||
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
|
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
|
||||||
import { useSwapContext, useSwapFair } from "./context/Swap";
|
import { useSwapContext, useSwapFair } from "./context/Swap";
|
||||||
import { useMarket, useOpenOrders, useDexContext } from "./context/Dex";
|
import { useMarket, useOpenOrders, useDexContext } from "./context/Dex";
|
||||||
import { useTokenList } from "./context/TokenList";
|
import { useTokenMap } from "./context/TokenList";
|
||||||
import { useMint } from "./context/Mint";
|
import { useMint } from "./context/Mint";
|
||||||
import { useOwnedTokenAccount } from "./context/Token";
|
import { useOwnedTokenAccount } from "./context/Token";
|
||||||
|
|
||||||
|
@ -298,17 +298,17 @@ function OpenOrdersRow({
|
||||||
const [ooAccount, setOoAccount] = useState(openOrders[0]);
|
const [ooAccount, setOoAccount] = useState(openOrders[0]);
|
||||||
const { swapClient } = useDexContext();
|
const { swapClient } = useDexContext();
|
||||||
const marketClient = useMarket(market);
|
const marketClient = useMarket(market);
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
const base = useMint(marketClient?.baseMintAddress);
|
const base = useMint(marketClient?.baseMintAddress);
|
||||||
const quote = useMint(marketClient?.quoteMintAddress);
|
const quote = useMint(marketClient?.quoteMintAddress);
|
||||||
const baseWallet = useOwnedTokenAccount(marketClient?.baseMintAddress);
|
const baseWallet = useOwnedTokenAccount(marketClient?.baseMintAddress);
|
||||||
const quoteWallet = useOwnedTokenAccount(marketClient?.quoteMintAddress);
|
const quoteWallet = useOwnedTokenAccount(marketClient?.quoteMintAddress);
|
||||||
const baseTicker = tokenList
|
const baseTicker = marketClient
|
||||||
.filter((t) => t.address === marketClient?.baseMintAddress.toString())
|
? tokenMap.get(marketClient?.baseMintAddress.toString())?.symbol
|
||||||
.map((t) => t.symbol)[0];
|
: "-";
|
||||||
const quoteTicker = tokenList
|
const quoteTicker = marketClient
|
||||||
.filter((t) => t.address === marketClient?.quoteMintAddress.toString())
|
? tokenMap.get(marketClient?.quoteMintAddress.toString())?.symbol
|
||||||
.map((t) => t.symbol)[0];
|
: "-";
|
||||||
const marketName =
|
const marketName =
|
||||||
baseTicker && quoteTicker
|
baseTicker && quoteTicker
|
||||||
? `${baseTicker} / ${quoteTicker}`
|
? `${baseTicker} / ${quoteTicker}`
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
useMarket,
|
useMarket,
|
||||||
} from "./context/Dex";
|
} from "./context/Dex";
|
||||||
import { MintContextProvider, useMint } from "./context/Mint";
|
import { MintContextProvider, useMint } from "./context/Mint";
|
||||||
import { TokenListContextProvider, useTokenList } from "./context/TokenList";
|
import { TokenListContextProvider, useTokenMap } from "./context/TokenList";
|
||||||
import { TokenContextProvider, useOwnedTokenAccount } from "./context/Token";
|
import { TokenContextProvider, useOwnedTokenAccount } from "./context/Token";
|
||||||
import TokenDialog from "./TokenDialog";
|
import TokenDialog from "./TokenDialog";
|
||||||
import { SettingsButton } from "./Settings";
|
import { SettingsButton } from "./Settings";
|
||||||
|
@ -228,8 +228,8 @@ function TokenButton({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
|
export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
let tokenInfo = tokenList.filter((t) => t.address === mint.toString())[0];
|
let tokenInfo = tokenMap.get(mint.toString());
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -238,8 +238,8 @@ export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tokenInfo.logoURI ? (
|
{tokenInfo?.logoURI ? (
|
||||||
<img alt="token logo" style={style} src={tokenInfo.logoURI} />
|
<img alt="token logo" style={style} src={tokenInfo?.logoURI} />
|
||||||
) : (
|
) : (
|
||||||
<div style={style}></div>
|
<div style={style}></div>
|
||||||
)}
|
)}
|
||||||
|
@ -248,10 +248,10 @@ export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function TokenName({ mint }: { mint: PublicKey }) {
|
function TokenName({ mint }: { mint: PublicKey }) {
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
let tokenInfo = tokenList.filter((t) => t.address === mint.toString())[0];
|
let tokenInfo = tokenMap.get(mint.toString());
|
||||||
return (
|
return (
|
||||||
<Typography style={{ marginLeft: "5px" }}>{tokenInfo.symbol}</Typography>
|
<Typography style={{ marginLeft: "5px" }}>{tokenInfo?.symbol}</Typography>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from "react";
|
import { useState, useMemo } from "react";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import {
|
import {
|
||||||
makeStyles,
|
makeStyles,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { TokenIcon } from "./Swap";
|
import { TokenIcon } from "./Swap";
|
||||||
import { useDexContext } from "./context/Dex";
|
import { useDexContext } from "./context/Dex";
|
||||||
import { useTokenList } from "./context/TokenList";
|
import { useTokenMap } from "./context/TokenList";
|
||||||
import { USDC_MINT, USDT_MINT } from "../utils/pubkeys";
|
import { USDC_MINT, USDT_MINT } from "../utils/pubkeys";
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
|
@ -39,6 +39,9 @@ export default function TokenDialog({
|
||||||
const [tokenFilter, setTokenFilter] = useState("");
|
const [tokenFilter, setTokenFilter] = useState("");
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const { swapClient } = useDexContext();
|
const { swapClient } = useDexContext();
|
||||||
|
const tokens = useMemo(() => {
|
||||||
|
return swapClient.tokens().concat([USDC_MINT, USDT_MINT]);
|
||||||
|
}, [swapClient]);
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
|
@ -64,10 +67,7 @@ export default function TokenDialog({
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<List disablePadding>
|
<List disablePadding>
|
||||||
{swapClient
|
{tokens.map((mint) => (
|
||||||
.tokens()
|
|
||||||
.concat([USDC_MINT, USDT_MINT])
|
|
||||||
.map((mint) => (
|
|
||||||
<TokenListItem
|
<TokenListItem
|
||||||
key={mint.toString()}
|
key={mint.toString()}
|
||||||
mint={mint}
|
mint={mint}
|
||||||
|
@ -101,13 +101,15 @@ function TokenListItem({
|
||||||
}
|
}
|
||||||
|
|
||||||
function TokenName({ mint }: { mint: PublicKey }) {
|
function TokenName({ mint }: { mint: PublicKey }) {
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
let tokenInfo = tokenList.filter((t) => t.address === mint.toString())[0];
|
let tokenInfo = tokenMap.get(mint.toString());
|
||||||
return (
|
return (
|
||||||
<div style={{ marginLeft: "16px" }}>
|
<div style={{ marginLeft: "16px" }}>
|
||||||
<Typography style={{ fontWeight: "bold" }}>{tokenInfo.symbol}</Typography>
|
<Typography style={{ fontWeight: "bold" }}>
|
||||||
|
{tokenInfo?.symbol}
|
||||||
|
</Typography>
|
||||||
<Typography color="textSecondary" style={{ fontSize: "14px" }}>
|
<Typography color="textSecondary" style={{ fontSize: "14px" }}>
|
||||||
{tokenInfo.name}
|
{tokenInfo?.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from "@project-serum/serum";
|
} from "@project-serum/serum";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { DEX_PID } from "../../utils/pubkeys";
|
import { DEX_PID } from "../../utils/pubkeys";
|
||||||
import { useTokenList } from "./TokenList";
|
import { useTokenMap } from "./TokenList";
|
||||||
|
|
||||||
type DexContext = {
|
type DexContext = {
|
||||||
// Maps market address to open orders accounts.
|
// Maps market address to open orders accounts.
|
||||||
|
@ -196,14 +196,14 @@ export function useOrderbook(market?: PublicKey): Orderbook | undefined {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMarketName(market: PublicKey): string {
|
export function useMarketName(market: PublicKey): string {
|
||||||
const tokenList = useTokenList();
|
const tokenMap = useTokenMap();
|
||||||
const marketClient = useMarket(market);
|
const marketClient = useMarket(market);
|
||||||
const baseTicker = tokenList
|
const baseTicker = marketClient
|
||||||
.filter((t) => t.address === marketClient?.baseMintAddress.toString())
|
? tokenMap.get(marketClient?.baseMintAddress.toString())?.symbol
|
||||||
.map((t) => t.symbol)[0];
|
: "-";
|
||||||
const quoteTicker = tokenList
|
const quoteTicker = marketClient
|
||||||
.filter((t) => t.address === marketClient?.quoteMintAddress.toString())
|
? tokenMap.get(marketClient?.quoteMintAddress.toString())?.symbol
|
||||||
.map((t) => t.symbol)[0];
|
: "-";
|
||||||
const name = `${baseTicker} / ${quoteTicker}`;
|
const name = `${baseTicker} / ${quoteTicker}`;
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,36 @@
|
||||||
import React, { useContext } from "react";
|
import React, { useContext, useMemo } from "react";
|
||||||
import { TokenListContainer, TokenInfo } from "@solana/spl-token-registry";
|
import { TokenInfo } from "@solana/spl-token-registry";
|
||||||
|
|
||||||
|
type TokenListContext = {
|
||||||
|
tokenMap: Map<string, TokenInfo>;
|
||||||
|
};
|
||||||
const _TokenListContext = React.createContext<null | TokenListContext>(null);
|
const _TokenListContext = React.createContext<null | TokenListContext>(null);
|
||||||
|
|
||||||
export function TokenListContextProvider(props: any) {
|
export function TokenListContextProvider(props: any) {
|
||||||
|
const tokenList = useMemo(() => props.tokenList.getList(), [props.tokenList]);
|
||||||
|
const tokenMap = useMemo(() => {
|
||||||
|
const tokenMap = new Map();
|
||||||
|
tokenList.forEach((t: TokenInfo) => {
|
||||||
|
tokenMap.set(t.address, t);
|
||||||
|
});
|
||||||
|
return tokenMap;
|
||||||
|
}, [tokenList]);
|
||||||
return (
|
return (
|
||||||
<_TokenListContext.Provider value={{ tokenList: props.tokenList }}>
|
<_TokenListContext.Provider value={{ tokenMap }}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</_TokenListContext.Provider>
|
</_TokenListContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenListContext = {
|
function useTokenListContext(): TokenListContext {
|
||||||
tokenList: TokenListContainer;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useTokenList(): TokenInfo[] {
|
|
||||||
const ctx = useContext(_TokenListContext);
|
const ctx = useContext(_TokenListContext);
|
||||||
if (ctx === null) {
|
if (ctx === null) {
|
||||||
throw new Error("Context not available");
|
throw new Error("Context not available");
|
||||||
}
|
}
|
||||||
return ctx.tokenList.getList();
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTokenMap(): Map<string, TokenInfo> {
|
||||||
|
const { tokenMap } = useTokenListContext();
|
||||||
|
return tokenMap;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue