I am trying to get the information of a pump.fun token, and I want to get the bonding curve progress percentage. but I don't know how to calculate it, is there any API to get the bonding curve progress information? I got the address of the bonding curve, can I use it to get the percentage using it? or anyone know what is the math behind calculating it?
1 Answer
To get bonding curve percentage you can use bitquery api url
According to the above link, we can calculate progress as follows
//We get totalReserves, realTokenReserves from bonding curve data
reservedTokens=206900000 // (without decimals)
initialRealTokenReserves = totalReserves - reservedTokens
leftTokens = realTokenReserves - reservedTokens
BondingCurveProgress = 100 - ((leftTokens*100)/(initialRealTokenReserves))
We can get same data from blockchain as well. To parse bonding curve account data, we need pump.fun idl. Here is link for the idl file. Posting it below as well
{
"version": "0.1.0",
"name": "pump",
"instructions": [
{
"name": "initialize",
"docs": [
"Creates the global state."
],
"accounts": [
{
"name": "global",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
},
{
"name": "setParams",
"docs": [
"Sets the global state parameters."
],
"accounts": [
{
"name": "global",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "feeRecipient",
"type": "publicKey"
},
{
"name": "initialVirtualTokenReserves",
"type": "u64"
},
{
"name": "initialVirtualSolReserves",
"type": "u64"
},
{
"name": "initialRealTokenReserves",
"type": "u64"
},
{
"name": "tokenTotalSupply",
"type": "u64"
},
{
"name": "feeBasisPoints",
"type": "u64"
}
]
},
{
"name": "create",
"docs": [
"Creates a new coin and bonding curve."
],
"accounts": [
{
"name": "mint",
"isMut": true,
"isSigner": true
},
{
"name": "mintAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "mplTokenMetadata",
"isMut": false,
"isSigner": false
},
{
"name": "metadata",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "associatedTokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "rent",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "name",
"type": "string"
},
{
"name": "symbol",
"type": "string"
},
{
"name": "uri",
"type": "string"
}
]
},
{
"name": "buy",
"docs": [
"Buys tokens from a bonding curve."
],
"accounts": [
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "feeRecipient",
"isMut": true,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedUser",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "rent",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "amount",
"type": "u64"
},
{
"name": "maxSolCost",
"type": "u64"
}
]
},
{
"name": "sell",
"docs": [
"Sells tokens into a bonding curve."
],
"accounts": [
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "feeRecipient",
"isMut": true,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedUser",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "associatedTokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "amount",
"type": "u64"
},
{
"name": "minSolOutput",
"type": "u64"
}
]
},
{
"name": "withdraw",
"docs": [
"Allows the admin to withdraw liquidity for a migration once the bonding curve completes"
],
"accounts": [
{
"name": "global",
"isMut": false,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "bondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedBondingCurve",
"isMut": true,
"isSigner": false
},
{
"name": "associatedUser",
"isMut": true,
"isSigner": false
},
{
"name": "user",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "rent",
"isMut": false,
"isSigner": false
},
{
"name": "eventAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "program",
"isMut": false,
"isSigner": false
}
],
"args": []
}
],
"accounts": [
{
"name": "Global",
"type": {
"kind": "struct",
"fields": [
{
"name": "initialized",
"type": "bool"
},
{
"name": "authority",
"type": "publicKey"
},
{
"name": "feeRecipient",
"type": "publicKey"
},
{
"name": "initialVirtualTokenReserves",
"type": "u64"
},
{
"name": "initialVirtualSolReserves",
"type": "u64"
},
{
"name": "initialRealTokenReserves",
"type": "u64"
},
{
"name": "tokenTotalSupply",
"type": "u64"
},
{
"name": "feeBasisPoints",
"type": "u64"
}
]
}
},
{
"name": "BondingCurve",
"type": {
"kind": "struct",
"fields": [
{
"name": "virtualTokenReserves",
"type": "u64"
},
{
"name": "virtualSolReserves",
"type": "u64"
},
{
"name": "realTokenReserves",
"type": "u64"
},
{
"name": "realSolReserves",
"type": "u64"
},
{
"name": "tokenTotalSupply",
"type": "u64"
},
{
"name": "complete",
"type": "bool"
}
]
}
}
],
"events": [
{
"name": "CreateEvent",
"fields": [
{
"name": "name",
"type": "string",
"index": false
},
{
"name": "symbol",
"type": "string",
"index": false
},
{
"name": "uri",
"type": "string",
"index": false
},
{
"name": "mint",
"type": "publicKey",
"index": false
},
{
"name": "bondingCurve",
"type": "publicKey",
"index": false
},
{
"name": "user",
"type": "publicKey",
"index": false
}
]
},
{
"name": "TradeEvent",
"fields": [
{
"name": "mint",
"type": "publicKey",
"index": false
},
{
"name": "solAmount",
"type": "u64",
"index": false
},
{
"name": "tokenAmount",
"type": "u64",
"index": false
},
{
"name": "isBuy",
"type": "bool",
"index": false
},
{
"name": "user",
"type": "publicKey",
"index": false
},
{
"name": "timestamp",
"type": "i64",
"index": false
},
{
"name": "virtualSolReserves",
"type": "u64",
"index": false
},
{
"name": "virtualTokenReserves",
"type": "u64",
"index": false
}
]
},
{
"name": "CompleteEvent",
"fields": [
{
"name": "user",
"type": "publicKey",
"index": false
},
{
"name": "mint",
"type": "publicKey",
"index": false
},
{
"name": "bondingCurve",
"type": "publicKey",
"index": false
},
{
"name": "timestamp",
"type": "i64",
"index": false
}
]
},
{
"name": "SetParamsEvent",
"fields": [
{
"name": "feeRecipient",
"type": "publicKey",
"index": false
},
{
"name": "initialVirtualTokenReserves",
"type": "u64",
"index": false
},
{
"name": "initialVirtualSolReserves",
"type": "u64",
"index": false
},
{
"name": "initialRealTokenReserves",
"type": "u64",
"index": false
},
{
"name": "tokenTotalSupply",
"type": "u64",
"index": false
},
{
"name": "feeBasisPoints",
"type": "u64",
"index": false
}
]
}
],
"errors": [
{
"code": 6000,
"name": "NotAuthorized",
"msg": "The given account is not authorized to execute this instruction."
},
{
"code": 6001,
"name": "AlreadyInitialized",
"msg": "The program is already initialized."
},
{
"code": 6002,
"name": "TooMuchSolRequired",
"msg": "slippage: Too much SOL required to buy the given amount of tokens."
},
{
"code": 6003,
"name": "TooLittleSolReceived",
"msg": "slippage: Too little SOL received to sell the given amount of tokens."
},
{
"code": 6004,
"name": "MintDoesNotMatchBondingCurve",
"msg": "The mint does not match the bonding curve."
},
{
"code": 6005,
"name": "BondingCurveComplete",
"msg": "The bonding curve has completed and liquidity migrated to raydium."
},
{
"code": 6006,
"name": "BondingCurveNotComplete",
"msg": "The bonding curve has not completed."
},
{
"code": 6007,
"name": "NotInitialized",
"msg": "The program is not initialized."
}
],
"metadata": {
"address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
}
}
The idl file will help us decode bonding curve data Below is typescript code to get bonding curve progress
import {Program,Wallet,AnchorProvider} from "@coral-xyz/anchor";
import * as web3 from '@solana/web3.js';
import bs58 from 'bs58';
import IDL from "./pump_idl.json" assert { type: "json" };
import Buffer from 'Buffer';
import BN from 'bn.js';
const bondingurveProgress=async (mintAddress, userPrivateKey)=>{
const pumpSwapPID=new web3.PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");
const userWallet= new Wallet(web3.Keypair.fromSecretKey(bs58.decode(userPrivateKey)));
const conn = new web3.Connection("https://api.mainnet-beta.solana.com",{commitment: "finalized"});
const provider=new AnchorProvider(conn, userWallet, {commitment: "processed",});
const program=new Program(IDL, pumpSwapPID, provider);
const [bondingCurve] = web3.PublicKey.findProgramAddressSync([Buffer.from("bonding-curve"), new web3.PublicKey(mintAddress).toBytes()],pumpSwapPID);
const data= await program.account.bondingCurve.fetch(bondingCurve);
//We multiply by 1000_000 as coin have value in 6 decimals
const reservedTokens=new BN(206900000).mul(new BN(1000_000));
const initialRealTokenReserves=data.tokenTotalSupply.sub(reservedTokens);
const bondingCurveProgress= new BN(100).sub(data.realTokenReserves.mul(new BN(100)).div(initialRealTokenReserves))
return bondingCurveProgress.toString(10)
}
//Run this by passing mint address & an account keypair to feed in anchor program object
bondingurveProgress(mintKey, userPrivateKey)