A big difference between (say) EVM chains and Solana is that (generally speaking) Solana 'read' functionality only returns a set of bytes. It's up to the client to interpret these bytes appropriately and understand what the underlying data is.
Most 'liquidity pool' providers in Solana use standard Token Accounts to store token balances associated with each pool. The binary layout of these token accounts is stable and public and you can find it here:
https://github.com/solana-labs/solana-program-library/blob/48fbb5b7c49ea35848442bba470b89331dea2b2b/token/js/src/state/account.ts#L59
Even simpler, if you know the address of the token account, you can use the getTokenAccountBalance()
instruction from the Connection
class in web3.js
to get the underlying balances:
> await conn.getTokenAccountBalance(new PublicKey("BTpvbpTArnekGgbXRqjfSvp7gENtHXvZCAwuUKQNYMeN"))
{
context: { apiVersion: '1.10.29', slot: 142423119 },
value: {
amount: '1495409380195030',
decimals: 9,
uiAmount: 1495409.38019503,
uiAmountString: '1495409.38019503'
}
}
>
You can even subscribe to these balance updates with onAccountChange
and interpret the underlying binary data you receive to get notified of changes to balances.
So the real question is, how do you find the underlying addresses of the token accounts associated with each liquidity pool?
There are actually two 'hard' steps here:
Find the address of the pool itself. For example, if I want the Orca GMT-USDC pool, how do I know that its underlying address is 46GcZFgznxUf6TpoCqJqzMpgMbbJPCAwNn8GThSt9qjC
?
Read the configuration of this pool at the address from (1) and determine the address of the underlying token accounts. For example, if I read the data at 46GcZFgznxUf6TpoCqJqzMpgMbbJPCAwNn8GThSt9qjC
(Orca GMT-USDC), how do I know the underlying token accounts are BTpvbpTArnekGgbXRqjfSvp7gENtHXvZCAwuUKQNYMeN
and DdBTJuiAXQQ7gLVXBXNPbVEG8g1avRxiJXhH5LhBytYW
.
There is no simple answer to both of these problems. Generally speaking, the best place to look is the SDKs of the providers (eg Orca, Saber etc), as they provide a static list of market addresses (1) and either a static list or a way to dynamically read the data in each market address (2).
If you want a 'one stop' solution, I suggest using the Jupiter Aggregator SDK, which has had to solve all of these problems. It has to solve for both (1) and (2) across all markets in Solana, even though it doesn't expose some of those solutions directly through its SDK API.