0

How to accurately calculate token price using bonding curves?

I'm fetching account info for the bonding curve:

from solders.pubkey import Pubkey
from construct import Struct, Int64ul
from solana.rpc.api import Client

RPC = "https://"
client = Client(RPC)

def get_data(bonding_curve: Pubkey):
    bonding_curve_struct = Struct(
        "virtualTokenReserves" / Int64ul,
        "virtualSolReserves" / Int64ul,
        "realTokenReserves" / Int64ul,
        "realSolReserves" / Int64ul,
        "tokenTotalSupply" / Int64ul
    )
    account_info = client.get_account_info(bonding_curve)            
    data = account_info.value.data
    parsed_data = bonding_curve_struct.parse(bytes(data))
    return parsed_data

And getting the following data:

virtualTokenReserves = 6966180631402821399
virtualSolReserves = 1072354522981932
realTokenReserves = 30018057771
realSolReserves = 792454522981932
tokenTotalSupply = 18057771

This is how I calculate token price before I do the transaction:

Token Price = real_token_reserves / virtual_sol_reserves  / 1000
Token Price = 0.00000002799266206 SOL

(/1000 is just for decimal places)

Altho this gives me a pretty close price, it is not exact.

I did a small test purchase (on a dead token no one trades on) after this calculation and got:

35723.647784 tokens for 0.001000034 SOL

If you do the math you get the actual token price used for this transaction:

Token Price = 0.00000002799361381 SOL

My calculated price and real price are pretty close, but they're not exact. Which leads to purchases like 0.001000034 SOL instead of 0.001 SOL.

I determine the amount I want to send in swap instruction data based on how much SOL I want to buy for and the token price that I get from bonding curve reserves. In this instance I want to buy for 0.001 SOL or sol_in_lamports = 1000000

amount = int(sol_in_lamports * virtual_sol_reserves / real_token_reserves)
amount = 35723647784   #amount needs to be int

If you multiply this amount by the token price I calculated, you get:

35723647784 * 0.00000002799266206 = 999.99999996797987504 = 0.001 SOL

So base on my calculations I should receive 0.001 SOL if I set amount = 35723647784 in swap instruction data.

Instead my transaction was done with Token Price = 0.00000002799361381 SOL and for same amount of tokens I paid:

35723647784 * 0.00000002799361381 = 1,000.03399994975829704 = 0.001000034 SOL

I did multiple tests like this for different coins and all the time my calculated token price is a bit lower than the actual price that gets used for transaction. As far as I understand it fees should be charged on top of that amount and slippage is only affecting the maxSolCost in swap instruction data, right?

Don't get me wrong, I'm not here to cry about how I pay a little bit extra. I just want to be able to send "rounded" transactions like 0.1 SOL, 0.025 SOL, etc, without these small extra bits at the end.

Would really appreciate if anyone can help me out with this or point me in the right direction. Thanks!

Additional questions:

-Can you somehow use the amount of SOL in swap instruction data instead? Like buy as much tokens as you can for X SOL, instead of buying Y tokens?

-Is there any other way to get token price from bonding curve without any APIs?

1 Answer 1

1

The main issue with your original calculation was that it didn't account for the constant product formula used by bonding curves aka delta

(x + Δx)(y - Δy) = xy

where x is the SOL reserves and y is the token reserves.

Delta = (New price of second trading pair - Original price of second trading pair) / (Change in price of first trading pair)

1
  • Thank you so much! This is the formula that worked for me: amount = int((sol_in_lamports * virtual_sol_reserves) / (real_token_reserves + sol_in_lamports))
    – mikile
    Commented Nov 30 at 14:31

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.