diff --git a/package.json b/package.json index 3f85014..1bc0001 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@project-serum/swap-ui", - "version": "0.1.0-alpha.11", + "version": "0.1.0-alpha.17", "main": "dist/index.js", "types": "dist/index.d.ts", "homepage": ".", diff --git a/src/swap/context/Dex.tsx b/src/swap/context/Dex.tsx index cc16914..f85ab92 100644 --- a/src/swap/context/Dex.tsx +++ b/src/swap/context/Dex.tsx @@ -1,6 +1,7 @@ import React, { useContext, useState, useEffect } from "react"; import { useAsync } from "react-async-hook"; import { TokenInfo } from "@solana/spl-token-registry"; +import { MintLayout } from "@solana/spl-token"; import { Connection, PublicKey } from "@solana/web3.js"; import * as anchor from "@project-serum/anchor"; import { Swap as SwapClient } from "@project-serum/swap"; @@ -21,6 +22,7 @@ import { } from "../utils/pubkeys"; import { useTokenMap, useTokenListContext } from "./TokenList"; import { fetchSolletInfo, requestWormholeSwapMarketIfNeeded } from "./Sollet"; +import { setMintCache } from "./Token"; export const BASE_TAKER_FEE_BPS = 0.0022; @@ -37,11 +39,11 @@ export function DexContextProvider(props: any) { ); const swapClient = props.swapClient; - // Two operations: + // Three operations: // // 1. Fetch all open orders accounts for the connected wallet. // 2. Batch fetch all market accounts for those open orders. - // + // 3. Batch fetch all mints associated with the markets. useEffect(() => { if (!swapClient.program.provider.wallet.publicKey) { setOoAccounts(new Map()); @@ -68,36 +70,55 @@ export function DexContextProvider(props: any) { "Too many markets. Please file an issue to update this" ); } - ( - await anchor.utils.getMultipleAccounts( - swapClient.program.provider.connection, - // @ts-ignore - [...markets].map((m) => new PublicKey(m)) - ) - ) - .map((programAccount) => { - return { - publicKey: programAccount?.publicKey, - account: new Promise((resolve) => - resolve( - new Market( - Market.getLayout(DEX_PID).decode( - programAccount?.account.data - ), - -1, // Not used so don't bother fetching. - -1, // Not used so don't bother fetching. - swapClient.program.provider.opts, - DEX_PID - ) - ) - ), - }; - }) - .forEach((m) => { - _MARKET_CACHE.set(m.publicKey!.toString(), m.account); - }); - + const multipleMarkets = await anchor.utils.getMultipleAccounts( + swapClient.program.provider.connection, + Array.from(markets.values()).map((m) => new PublicKey(m)) + ); + const marketClients = multipleMarkets.map((programAccount) => { + return { + publicKey: programAccount?.publicKey, + account: new Market( + Market.getLayout(DEX_PID).decode(programAccount?.account.data), + -1, // Not used so don't bother fetching. + -1, // Not used so don't bother fetching. + swapClient.program.provider.opts, + DEX_PID + ), + }; + }); + marketClients.forEach((m) => { + _MARKET_CACHE.set( + m.publicKey!.toString(), + new Promise((resolve) => resolve(m.account)) + ); + }); setOoAccounts(newOoAccounts); + + // Batch fetch all the mints, since we know we'll need them at some + // point. + const mintPubkeys = Array.from( + new Set( + marketClients + .map((m) => [ + m.account.baseMintAddress.toString(), + m.account.quoteMintAddress.toString(), + ]) + .flat() + ).values() + ).map((pk) => new PublicKey(pk)); + + if (mintPubkeys.length > 100) { + // Punt request chunking until there's user demand. + throw new Error("Too many mints. Please file an issue to update this"); + } + + const mints = await anchor.utils.getMultipleAccounts( + swapClient.program.provider.connection, + mintPubkeys + ); + mints.forEach((mint) => { + setMintCache(mint!.publicKey, MintLayout.decode(mint!.account.data)); + }); }); }, [ swapClient.program.provider.connection, diff --git a/src/swap/context/Token.tsx b/src/swap/context/Token.tsx index b98e778..523a3fe 100644 --- a/src/swap/context/Token.tsx +++ b/src/swap/context/Token.tsx @@ -141,6 +141,10 @@ export function useMint(mint?: PublicKey): MintInfo | undefined | null { return undefined; } +export function setMintCache(pk: PublicKey, account: MintInfo) { + _MINT_CACHE.set(pk.toString(), new Promise((resolve) => resolve(account))); +} + // Cache storing all token accounts for the connected wallet provider. const _OWNED_TOKEN_ACCOUNTS_CACHE: Array<{ publicKey: PublicKey; diff --git a/src/swap/utils/tokens.ts b/src/swap/utils/tokens.ts index bcdbd78..2890c44 100644 --- a/src/swap/utils/tokens.ts +++ b/src/swap/utils/tokens.ts @@ -70,12 +70,6 @@ const ACCOUNT_LAYOUT = BufferLayout.struct([ BufferLayout.blob(93), ]); -const MINT_LAYOUT = BufferLayout.struct([ - BufferLayout.blob(44), - BufferLayout.u8("decimals"), - BufferLayout.blob(37), -]); - export function parseTokenAccountData(data: Buffer): TokenAccount { // @ts-ignore let { mint, owner, amount } = ACCOUNT_LAYOUT.decode(data); @@ -87,12 +81,6 @@ export function parseTokenAccountData(data: Buffer): TokenAccount { }; } -export function parseMintData(data: Buffer) { - // @ts-ignore - let { decimals } = MINT_LAYOUT.decode(data); - return { decimals }; -} - function getOwnedAccountsFilters(publicKey: PublicKey) { return [ {