From fbd8396c827ff91fc282effe8f7f0f8011ce2dd7 Mon Sep 17 00:00:00 2001 From: Philippe Maes Date: Sat, 29 Aug 2020 17:32:49 +0200 Subject: [PATCH] All market balances --- src/pages/BalancesPage.jsx | 4 +- src/utils/markets.js | 132 +++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/pages/BalancesPage.jsx b/src/pages/BalancesPage.jsx index 076a1a7..9c77533 100644 --- a/src/pages/BalancesPage.jsx +++ b/src/pages/BalancesPage.jsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useBalances } from '../utils/markets'; +import { useBalancesForAllMarkets } from '../utils/markets'; import FloatingElement from '../components/layout/FloatingElement'; import BalancesTable from '../components/UserInfoTable/BalancesTable'; export default function BalancesPage() { - const balances = useBalances(); + const balances = useBalancesForAllMarkets(); return ( diff --git a/src/utils/markets.js b/src/utils/markets.js index 773ad88..018bb69 100644 --- a/src/utils/markets.js +++ b/src/utils/markets.js @@ -52,13 +52,21 @@ export function useAllMarkets() { const marketList = Object.values(MARKET_INFO_BY_NAME); let marketInfo; for (marketInfo of marketList) { - const market = await Market.load( - connection, - new PublicKey(marketInfo.address), - {}, - new PublicKey(selectedDexProgramID), - ); - markets.push({ market, marketName: marketInfo.name }); + try { + const market = await Market.load( + connection, + new PublicKey(marketInfo.address), + {}, + new PublicKey(selectedDexProgramID), + ); + markets.push({ market, marketName: marketInfo.name }); + } catch (e) { + notify({ + message: 'Error loading market', + description: e.message, + type: 'error', + }); + } } setMarkets(markets); }; @@ -583,3 +591,113 @@ export function useBalances() { }, ]; } + +export function useBalancesForAllMarkets() { + const [connected, wallet] = useWallet(); + + const connection = useConnection(); + const allMarkets = useAllMarkets(); + + async function getBalancesForAllMarkets() { + let balances = []; + if (!connected) { + return balances; + } + + let marketData; + for (marketData of allMarkets) { + const { market, marketName } = marketData; + if (!market) { + return balances; + } + const baseCurrency = marketName.includes('/') && marketName.split('/')[0]; + if (!balances.find((balance) => balance.coin === baseCurrency)) { + const baseBalance = await getBalanceForMarket( + market, + connection, + wallet, + baseCurrency, + true, + ); + balances.push(baseBalance); + } + const quoteCurrency = + marketName.includes('/') && marketName.split('/')[1]; + if (!balances.find((balance) => balance.coin === quoteCurrency)) { + const quoteBalance = await getBalanceForMarket( + market, + connection, + wallet, + quoteCurrency, + false, + ); + balances.push(quoteBalance); + } + } + + return balances; + } + + return useAsyncData( + getBalancesForAllMarkets, + tuple( + 'getBalancesForAllMarkets', + connected, + connection, + wallet, + allMarkets, + ), + { refreshInterval: _SLOW_REFRESH_INTERVAL }, + ); +} + +async function getBalanceForMarket( + market, + connection, + wallet, + currency, + base = true, +) { + if (!market) { + return; + } + const findTokenAccountsForOwner = base + ? market.findBaseTokenAccountsForOwner + : market.findQuoteTokenAccountsForOwner; + const currencyAccounts = await findTokenAccountsForOwner( + connection, + wallet.publicKey, + ); + const currencyAccount = currencyAccounts && currencyAccounts[0]; + const currencyBalances = await connection.getTokenAccountBalance( + currencyAccount.pubkey, + ); + const openOrdersAccounts = await market.findOpenOrdersAccountsForOwner( + connection, + wallet.publicKey, + ); + const openOrdersAccount = openOrdersAccounts && openOrdersAccounts[0]; + const inOrders = base + ? openOrdersAccount?.baseTokenTotal && + openOrdersAccount?.baseTokenFree && + market.baseSplSizeToNumber( + openOrdersAccount.baseTokenTotal.sub(openOrdersAccount.baseTokenFree), + ) + : openOrdersAccount?.quoteTokenTotal && + openOrdersAccount?.quoteTokenFree && + market.quoteSplSizeToNumber( + openOrdersAccount.quoteTokenTotal.sub(openOrdersAccount.quoteTokenFree), + ); + const unsettled = base + ? openOrdersAccount?.baseTokenFree && + market.baseSplSizeToNumber(openOrdersAccount.baseTokenFree) + : openOrdersAccount?.quoteTokenFree && + market.baseSplSizeToNumber(openOrdersAccount.baseTokenFree); + return { + key: currency, + coin: currency, + wallet: currencyBalances, + orders: inOrders, + unsettled: unsettled, + }; +}