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?