3

On EVM networks you can query the blockchain for the balance of the LP pair reserves (token0, token1) and calculate prices from there.

How do I replicate something similar on the solana blockchain. I've looked in all documentation I can't get any values to return for LP pairs or something similar.. if anyone can point me in the right direction where you would normally find that information.

Thanks in advance,

K.

3 Answers 3

5

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:

  1. 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?

  2. 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.

4

Most token swap apps available on Solana are using a program that comes with Solana, the Token Swap Program.

It has an option to use the Constant Product pricing model, which is the most popular (along with stablecoin pricing).

Source code available on Github.

Each pool has a pool authority, which is a PDA (program derived address) account that stores all pool state.

If you are interested in querying the state of a specific pool on some specific DEX, I would get in contact with the developers of the DEX and ask for the address of their pool authority, which you can then query in any of the Solana explorers. You would need to find out about the layout of data within the PDA. Since the base Token Swap Program is open source, you can probably figure it out from there.

2
  • Thanks for this. I'll do some testing with the above information.
    – 0xKRN
    Commented Jul 20, 2022 at 16:10
  • SPL Token Swap is a reference implementation. It doesn't "come with Solana," nor is there any "official" deployment of the program. All deployments are third-party forks of that reference code base
    – trent.sol
    Commented Jul 20, 2022 at 20:17
4

You should always use an oracle to get the price of LP tokens. There has been a number of DeFi hacks related to using flash loans to skew the LP pool reserves and manipulate the LP token price in the attackers favor.

Switchboard wrote an article on this, https://switchboardxyz.medium.com/fair-lp-token-oracles-94a457c50239

Full transparency, I am from the Switchboard team and wrote the article.

To answer your question, each LP pool is different. You will need to consult their SDK to figure out how they store the data on-chain. Here is how we do it for Orca on the client side.

import {
  getOrca,
  getTokenCount,
  Orca,
  OrcaPool,
  OrcaPoolConfig,
  OrcaPoolToken,
  OrcaToken,
  OrcaU64,
} from "@orca-so/sdk";
import { orcaPoolConfigs } from "@orca-so/sdk/dist/constants/pools.js";
import { usdcToken } from "@orca-so/sdk/dist/constants/tokens.js";
import { OrcaPoolParams } from "@orca-so/sdk/dist/model/orca/pool/pool-types.js";

const poolConfig = orcaPoolConfigs[
  k
].poolTokenMint.toString() as OrcaPoolConfig;
const pool = this.orca.getPool(poolConfig);
const poolParameters = orcaPoolConfigs[poolConfig];
const tokenA = pool.getTokenA();
const tokenB = pool.getTokenB();

const orcaSupply = await pool.getLPSupply();
const tokenSupply = fromBN(
  new anchor.BN(orcaSupply.value),
  orcaSupply.scale
);

// get current amount of each token in the pool
const tokenCount = await getTokenCount(
  this.connection,
  poolParameters,
  tokenA,
  tokenB
);
const r0 = fromBN(new anchor.BN(tokenCount.inputTokenCount), tokenA.scale);
const r1 = fromBN(new anchor.BN(tokenCount.outputTokenCount), tokenB.scale);

// ... then send the values to the fair LP pricing formula

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.