diff --git a/debug-ui/app/components/AppWalletProvider.tsx b/debug-ui/app/components/AppWalletProvider.tsx index cd6c321c5..a974d8a66 100644 --- a/debug-ui/app/components/AppWalletProvider.tsx +++ b/debug-ui/app/components/AppWalletProvider.tsx @@ -21,6 +21,7 @@ import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'; import WalletConnection from './WalletConnection'; import { ManifestClient, Market } from '@cks-systems/manifest-sdk'; import { + AccountInfo, Connection, GetProgramAccountsResponse, PublicKey, @@ -32,7 +33,7 @@ import { getClusterFromConnection, } from '@cks-systems/manifest-sdk/utils/solana'; import NavBar from './NavBar'; -import { LabelsByAddr } from '@/lib/types'; +import { ActiveByAddr, LabelsByAddr, VolumeByAddr } from '@/lib/types'; import { fetchAndSetMfxAddrLabels } from '@/lib/address-labels'; require('react-toastify/dist/ReactToastify.css'); @@ -42,11 +43,13 @@ interface AppStateContextValue { loading: boolean; network: WalletAdapterNetwork | null; marketAddrs: string[]; - marketVolumes: [string, number][]; labelsByAddr: LabelsByAddr; + activeByAddr: ActiveByAddr; + marketVolumes: VolumeByAddr; setMarketAddrs: Dispatch>; setLabelsByAddr: Dispatch>; - setMarketVolumes: Dispatch>; + setActiveByAddr: Dispatch>; + setMarketVolumes: Dispatch>; } const AppStateContext = createContext( @@ -68,8 +71,9 @@ const AppWalletProvider = ({ }): ReactElement => { const [network, setNetwork] = useState(null); const [marketAddrs, setMarketAddrs] = useState([]); - const [marketVolumes, setMarketVolumes] = useState<[string, number][]>([]); + const [marketVolumes, setMarketVolumes] = useState({}); const [labelsByAddr, setLabelsByAddr] = useState({}); + const [activeByAddr, setActiveByAddr] = useState({}); const [loading, setLoading] = useState(false); const setupRun = useRef(false); @@ -123,8 +127,11 @@ const AppWalletProvider = ({ (a) => a.pubkey, ); const marketAddrs: string[] = marketPubs.map((p) => p.toBase58()); - const marketVolumes: [string, number][] = marketProgramAccounts.map( - (a) => { + const volumeByAddr: VolumeByAddr = {}; + marketProgramAccounts.forEach( + ( + a: Readonly<{ account: AccountInfo; pubkey: PublicKey }>, + ) => { const market: Market = Market.loadFromBuffer({ address: a.pubkey, buffer: a.account.data, @@ -133,16 +140,59 @@ const AppWalletProvider = ({ market.quoteMint().toBase58() == 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ) { - return [ - market.address.toBase58(), - Number(market.quoteVolume()) / 10 ** 6, - ]; + volumeByAddr[market.address.toBase58()] = + Number(market.quoteVolume()) / 10 ** 6; + } else { + volumeByAddr[market.address.toBase58()] = 0; } - return [market.address.toBase58(), 0]; }, ); setMarketAddrs(marketAddrs); - setMarketVolumes(marketVolumes); + setMarketVolumes(volumeByAddr); + + // Fine to do an N^2 search until the number of markets gets too big. + const activeByAddr: ActiveByAddr = {}; + marketProgramAccounts.forEach( + ( + acct1: Readonly<{ + account: AccountInfo; + pubkey: PublicKey; + }>, + ) => { + const market: Market = Market.loadFromBuffer({ + address: acct1.pubkey, + buffer: acct1.account.data, + }); + let foundBigger: boolean = false; + + marketProgramAccounts.forEach( + ( + acct2: Readonly<{ + account: AccountInfo; + pubkey: PublicKey; + }>, + ) => { + const market2: Market = Market.loadFromBuffer({ + address: acct2.pubkey, + buffer: acct2.account.data, + }); + if ( + market.baseMint().toString() == + market2.baseMint().toString() && + market.quoteMint().toString() == + market2.quoteMint().toString() && + volumeByAddr[market2.address.toBase58()] > + volumeByAddr[market.address.toBase58()] + ) { + foundBigger = true; + } + }, + ); + activeByAddr[market.address.toBase58()] = !foundBigger; + }, + ); + setActiveByAddr(activeByAddr); + fetchAndSetMfxAddrLabels(conn, marketAddrs, setLabelsByAddr); } catch (e) { console.error('fetching app state:', e); @@ -175,10 +225,12 @@ const AppWalletProvider = ({ network, marketAddrs, marketVolumes, + activeByAddr, labelsByAddr, setLabelsByAddr, setMarketAddrs, setMarketVolumes, + setActiveByAddr, loading, }} > diff --git a/debug-ui/app/page.tsx b/debug-ui/app/page.tsx index 0be4968e3..20cf501ad 100644 --- a/debug-ui/app/page.tsx +++ b/debug-ui/app/page.tsx @@ -7,8 +7,8 @@ import { addrToLabel } from '@/lib/address-labels'; const Home = (): ReactElement => { const readOnly = process.env.NEXT_PUBLIC_READ_ONLY === 'true'; - const { marketAddrs, loading, labelsByAddr, marketVolumes } = useAppState(); - const marketVolumesMap: Map = new Map(marketVolumes); + const { marketAddrs, loading, labelsByAddr, marketVolumes, activeByAddr } = + useAppState(); return (
@@ -32,22 +32,25 @@ const Home = (): ReactElement => { Existing Markets
    - {marketAddrs.map((market, index) => ( -
  • - - {addrToLabel(market, labelsByAddr)} - - {marketVolumesMap.get(market) != 0 - ? ': $' + marketVolumesMap.get(market)?.toFixed(2) - : ''} -
  • - ))} + {marketAddrs.map( + (market, index) => + activeByAddr[market] && ( +
  • + + {addrToLabel(market, labelsByAddr)} + + {marketVolumes[market] != 0 + ? ': $' + marketVolumes[market]?.toFixed(2) + : ''} +
  • + ), + )}
) : ( diff --git a/debug-ui/lib/types.ts b/debug-ui/lib/types.ts index 085862206..35df6b30a 100644 --- a/debug-ui/lib/types.ts +++ b/debug-ui/lib/types.ts @@ -2,6 +2,17 @@ export interface LabelsByAddr { [addr: string]: string; } +// When true, this is the primary market for a given pair. This is defined by +// quote volume traded and determines which is shown in UI. +// TODO: Make a toggle for show all +export interface ActiveByAddr { + [addr: string]: boolean; +} + +export interface VolumeByAddr { + [addr: string]: number; +} + export type FillResultUi = { market: string; maker: string;