Use memoized token map

This commit is contained in:
armaniferrante 2021-05-15 16:16:28 -07:00
parent 65467d00ea
commit ef97779a84
No known key found for this signature in database
GPG Key ID: 58BEF301E91F7828
7 changed files with 92 additions and 86 deletions

View File

@ -24,25 +24,9 @@ import "./App.css";
// to the `Swap` component, and then everything else is taken care of.
function App() {
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}>
<AppInner />
</SnackbarProvider>
</div>
<SnackbarProvider maxSnack={5} autoHideDuration={8000}>
<AppInner />
</SnackbarProvider>
);
}
@ -106,7 +90,21 @@ function AppInner() {
}, [wallet, enqueueSnackbar]);
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
variant="outlined"
onClick={() => (!isConnected ? wallet.connect() : wallet.disconnect())}

View File

@ -8,7 +8,7 @@ import {
import { Info } from "@material-ui/icons";
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
import { PublicKey } from "@solana/web3.js";
import { useTokenList } from "./context/TokenList";
import { useTokenMap } from "./context/TokenList";
import { useSwapContext, useSwapFair } from "./context/Swap";
import { useMint } from "./context/Mint";
import { useDexContext, useMarketName, useFair } from "./context/Dex";
@ -41,18 +41,16 @@ export function InfoLabel() {
const fromMintInfo = useMint(fromMint);
const fair = useSwapFair();
const tokenList = useTokenList();
let fromTokenInfo = tokenList.filter(
(t) => t.address === fromMint.toString()
)[0];
let toTokenInfo = tokenList.filter((t) => t.address === toMint.toString())[0];
const tokenMap = useTokenMap();
let fromTokenInfo = tokenMap.get(fromMint.toString());
let toTokenInfo = tokenMap.get(toMint.toString());
return (
<div className={styles.infoLabel}>
<Typography color="textSecondary"></Typography>
<div style={{ display: "flex" }}>
<div className={styles.fairPriceLabel}>
{fair !== undefined
{fair !== undefined && toTokenInfo && fromTokenInfo
? `1 ${toTokenInfo.symbol} = ${fair.toFixed(
fromMintInfo?.decimals
)} ${fromTokenInfo.symbol}`
@ -103,13 +101,9 @@ function InfoButton() {
function InfoDetails() {
const { fromMint, toMint } = useSwapContext();
const { swapClient } = useDexContext();
const tokenList = useTokenList();
const fromMintTicker = tokenList
.filter((t) => t.address === fromMint.toString())
.map((t) => t.symbol)[0];
const toMintTicker = tokenList
.filter((t) => t.address === toMint.toString())
.map((t) => t.symbol)[0];
const tokenMap = useTokenMap();
const fromMintTicker = tokenMap.get(fromMint.toString())?.symbol;
const toMintTicker = tokenMap.get(toMint.toString())?.symbol;
const addresses = [
{ ticker: fromMintTicker, mint: fromMint },
{ ticker: toMintTicker, mint: toMint },

View File

@ -32,7 +32,7 @@ import { SettingsOutlined as Settings, Close } from "@material-ui/icons";
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
import { useSwapContext, useSwapFair } from "./context/Swap";
import { useMarket, useOpenOrders, useDexContext } from "./context/Dex";
import { useTokenList } from "./context/TokenList";
import { useTokenMap } from "./context/TokenList";
import { useMint } from "./context/Mint";
import { useOwnedTokenAccount } from "./context/Token";
@ -298,17 +298,17 @@ function OpenOrdersRow({
const [ooAccount, setOoAccount] = useState(openOrders[0]);
const { swapClient } = useDexContext();
const marketClient = useMarket(market);
const tokenList = useTokenList();
const tokenMap = useTokenMap();
const base = useMint(marketClient?.baseMintAddress);
const quote = useMint(marketClient?.quoteMintAddress);
const baseWallet = useOwnedTokenAccount(marketClient?.baseMintAddress);
const quoteWallet = useOwnedTokenAccount(marketClient?.quoteMintAddress);
const baseTicker = tokenList
.filter((t) => t.address === marketClient?.baseMintAddress.toString())
.map((t) => t.symbol)[0];
const quoteTicker = tokenList
.filter((t) => t.address === marketClient?.quoteMintAddress.toString())
.map((t) => t.symbol)[0];
const baseTicker = marketClient
? tokenMap.get(marketClient?.baseMintAddress.toString())?.symbol
: "-";
const quoteTicker = marketClient
? tokenMap.get(marketClient?.quoteMintAddress.toString())?.symbol
: "-";
const marketName =
baseTicker && quoteTicker
? `${baseTicker} / ${quoteTicker}`

View File

@ -21,7 +21,7 @@ import {
useMarket,
} from "./context/Dex";
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 TokenDialog from "./TokenDialog";
import { SettingsButton } from "./Settings";
@ -228,8 +228,8 @@ function TokenButton({
}
export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
const tokenList = useTokenList();
let tokenInfo = tokenList.filter((t) => t.address === mint.toString())[0];
const tokenMap = useTokenMap();
let tokenInfo = tokenMap.get(mint.toString());
return (
<div
style={{
@ -238,8 +238,8 @@ export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
flexDirection: "column",
}}
>
{tokenInfo.logoURI ? (
<img alt="token logo" style={style} src={tokenInfo.logoURI} />
{tokenInfo?.logoURI ? (
<img alt="token logo" style={style} src={tokenInfo?.logoURI} />
) : (
<div style={style}></div>
)}
@ -248,10 +248,10 @@ export function TokenIcon({ mint, style }: { mint: PublicKey; style: any }) {
}
function TokenName({ mint }: { mint: PublicKey }) {
const tokenList = useTokenList();
let tokenInfo = tokenList.filter((t) => t.address === mint.toString())[0];
const tokenMap = useTokenMap();
let tokenInfo = tokenMap.get(mint.toString());
return (
<Typography style={{ marginLeft: "5px" }}>{tokenInfo.symbol}</Typography>
<Typography style={{ marginLeft: "5px" }}>{tokenInfo?.symbol}</Typography>
);
}

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useMemo } from "react";
import { PublicKey } from "@solana/web3.js";
import {
makeStyles,
@ -12,7 +12,7 @@ import {
} from "@material-ui/core";
import { TokenIcon } from "./Swap";
import { useDexContext } from "./context/Dex";
import { useTokenList } from "./context/TokenList";
import { useTokenMap } from "./context/TokenList";
import { USDC_MINT, USDT_MINT } from "../utils/pubkeys";
const useStyles = makeStyles(() => ({
@ -39,6 +39,9 @@ export default function TokenDialog({
const [tokenFilter, setTokenFilter] = useState("");
const styles = useStyles();
const { swapClient } = useDexContext();
const tokens = useMemo(() => {
return swapClient.tokens().concat([USDC_MINT, USDT_MINT]);
}, [swapClient]);
return (
<Dialog
open={open}
@ -64,19 +67,16 @@ export default function TokenDialog({
/>
<div>
<List disablePadding>
{swapClient
.tokens()
.concat([USDC_MINT, USDT_MINT])
.map((mint) => (
<TokenListItem
key={mint.toString()}
mint={mint}
onClick={(mint) => {
setMint(mint);
onClose();
}}
/>
))}
{tokens.map((mint) => (
<TokenListItem
key={mint.toString()}
mint={mint}
onClick={(mint) => {
setMint(mint);
onClose();
}}
/>
))}
</List>
</div>
</DialogContent>
@ -101,13 +101,15 @@ function TokenListItem({
}
function TokenName({ mint }: { mint: PublicKey }) {
const tokenList = useTokenList();
let tokenInfo = tokenList.filter((t) => t.address === mint.toString())[0];
const tokenMap = useTokenMap();
let tokenInfo = tokenMap.get(mint.toString());
return (
<div style={{ marginLeft: "16px" }}>
<Typography style={{ fontWeight: "bold" }}>{tokenInfo.symbol}</Typography>
<Typography style={{ fontWeight: "bold" }}>
{tokenInfo?.symbol}
</Typography>
<Typography color="textSecondary" style={{ fontSize: "14px" }}>
{tokenInfo.name}
{tokenInfo?.name}
</Typography>
</div>
);

View File

@ -9,7 +9,7 @@ import {
} from "@project-serum/serum";
import { PublicKey } from "@solana/web3.js";
import { DEX_PID } from "../../utils/pubkeys";
import { useTokenList } from "./TokenList";
import { useTokenMap } from "./TokenList";
type DexContext = {
// Maps market address to open orders accounts.
@ -196,14 +196,14 @@ export function useOrderbook(market?: PublicKey): Orderbook | undefined {
}
export function useMarketName(market: PublicKey): string {
const tokenList = useTokenList();
const tokenMap = useTokenMap();
const marketClient = useMarket(market);
const baseTicker = tokenList
.filter((t) => t.address === marketClient?.baseMintAddress.toString())
.map((t) => t.symbol)[0];
const quoteTicker = tokenList
.filter((t) => t.address === marketClient?.quoteMintAddress.toString())
.map((t) => t.symbol)[0];
const baseTicker = marketClient
? tokenMap.get(marketClient?.baseMintAddress.toString())?.symbol
: "-";
const quoteTicker = marketClient
? tokenMap.get(marketClient?.quoteMintAddress.toString())?.symbol
: "-";
const name = `${baseTicker} / ${quoteTicker}`;
return name;
}

View File

@ -1,24 +1,36 @@
import React, { useContext } from "react";
import { TokenListContainer, TokenInfo } from "@solana/spl-token-registry";
import React, { useContext, useMemo } from "react";
import { TokenInfo } from "@solana/spl-token-registry";
type TokenListContext = {
tokenMap: Map<string, TokenInfo>;
};
const _TokenListContext = React.createContext<null | TokenListContext>(null);
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 (
<_TokenListContext.Provider value={{ tokenList: props.tokenList }}>
<_TokenListContext.Provider value={{ tokenMap }}>
{props.children}
</_TokenListContext.Provider>
);
}
type TokenListContext = {
tokenList: TokenListContainer;
};
export function useTokenList(): TokenInfo[] {
function useTokenListContext(): TokenListContext {
const ctx = useContext(_TokenListContext);
if (ctx === null) {
throw new Error("Context not available");
}
return ctx.tokenList.getList();
return ctx;
}
export function useTokenMap(): Map<string, TokenInfo> {
const { tokenMap } = useTokenListContext();
return tokenMap;
}