Im trying to unpack bonding curve info from Solana using the API but it I am not sure how to best unpack this data. I have this code below. Im trying to get a price for a token using the bonding curve virtual_sol_reserves, virtual_token_reserves
async def fetch_bonding_curve_reserves(bonding_curve_address, async_solana_client):
max_retries = 6
retry_delay = 5
for attempt in range(max_retries):
try:
account_info = await async_solana_client.get_account_info(bonding_curve_address)
if not account_info.value:
logger.error(f"No account data available for {bonding_curve_address}")
raise ValueError("No account data available")
account_data = account_info.value.data
logger.debug(f"Raw account data for {bonding_curve_address}: {account_data}")
if isinstance(account_data, list):
logger.debug(f"Account data is a list of length {len(account_data)}")
if len(account_data) > 0:
account_data = account_data[0]
logger.debug(f"Using first element of the list as account data")
else:
logger.error(f"Account data list is empty for {bonding_curve_address}")
raise ValueError("Account data list is empty")
if isinstance(account_data, str):
logger.debug(f"Account data is a string, converting to bytes")
account_data = bytes(account_data, 'utf-8')
logger.debug(f"Account data type: {type(account_data)}")
logger.debug(f"Raw account data: {account_data}")
logger.debug(f"Raw account data (hex): {account_data.hex()}")
if isinstance(account_data, bytes):
try:
if len(account_data) >= 16: # Ensure there are enough bytes
logger.war(f"Raw account data (hex): {account_data.hex()}")
virtual_sol_reserves, virtual_token_reserves = struct.unpack("<QQ", account_data[:16])
logger.info(f"Retrieved reserves for {bonding_curve_address}:")
logger.info(f" virtual_sol_reserves: {virtual_sol_reserves}")
logger.info(f" virtual_token_reserves: {virtual_token_reserves}")
# Sanity check on the values
if virtual_sol_reserves > 1e18 or virtual_token_reserves > 1e18:
logger.warning("Unpacked values are unusually high, please verify the account data structure.")
raise ValueError("Unpacked values are unusually high")
sol_price_usd = await fetch_current_sol_price_in_usd()
token_price_sol = get_price_from_reserves(virtual_sol_reserves, virtual_token_reserves)
token_price_usd = token_price_sol * sol_price_usd if sol_price_usd is not None else None
return virtual_sol_reserves, virtual_token_reserves, token_price_sol, token_price_usd
else:
logger.error(f"Account data length is insufficient for unpacking: {len(account_data)} bytes")
raise ValueError("Account data length is insufficient for unpacking")
except struct.error as e:
logger.error(f"Failed to unpack account data for {bonding_curve_address}: {e}")
raise ValueError("Failed to unpack account data")
else:
logger.error(f"Unexpected data type for account data: {type(account_data)}")
raise TypeError("Unexpected data type for account data")
except Exception as e:
logger.error(f"Attempt {attempt + 1} failed for {bonding_curve_address}: {e}")
if attempt < max_retries - 1:
await asyncio.sleep(retry_delay)
else:
return None, None, None, None
return None, None, None, None
additional function
def get_price_from_reserves(virtual_sol_reserves, virtual_token_reserves):
try:
if virtual_token_reserves == 0:
logger.warning("Virtual token reserves are zero. Returning price as 0.")
return Decimal(0)
logger.debug(f"Calculating price from reserves: virtual_sol_reserves={virtual_sol_reserves}, virtual_token_reserves={virtual_token_reserves}")
token_price = Decimal(virtual_sol_reserves) / Decimal(virtual_token_reserves)
logger.info(f"Token price (before conversion): {token_price}")
token_price_sol = token_price / Decimal(LAMPORTS_PER_SOL)
logger.info(f"Token price (in SOL): {token_price_sol}")
return token_price_sol
except Exception as e:
logger.error(f"Error calculating price from reserves: {e}")
return None
Then we try to calculate token price
async def calculate_token_price(bonding_curve_address, async_solana_client):
sol_reserves, token_reserves = await fetch_bonding_curve_reserves(bonding_curve_address, async_solana_client)
if sol_reserves is None or token_reserves is None:
return None, None
sol_price_usd = await fetch_current_sol_price_in_usd()
if sol_price_usd is None:
return None, None
token_price_sol = sol_reserves / token_reserves
token_price_usd = token_price_sol * sol_price_usd
return token_price_sol.quantize(Decimal('.000000000000000001')), token_price_usd.quantize(Decimal('.000000000000000001'))
Ive had different values twice in terms of the size of the number, but I think the main issue here is how the data is being unpacked wrong so I cant get the correct token price my logs HTTP Request: POST https://api.mainnet-beta.solana.com “HTTP/1.1 200 OK”
2024-05-21 02:27:33,465 – Attempt 6: SOL reserves: 6966180631402821399, Token reserves: 1005937500000001
2024-05-21 02:27:33,465 – Unusually high values detected, attempt {attempt+1}
Thanks for your help in advance. Been on this for far too long
Im expecting to get get correct values for virtual_sol_reserves, virtual_token_reserves