Understand how Pump's constant-product bonding curve prices tokens and how to calculate trades off-chain.
Pump uses a constant-product bonding curve, similar to Uniswap's x * y = k:
The price at any point is:
As tokens are bought, virtualTokenReserves decreases and virtualSolReserves increases, pushing the price up.
import { BondingCurve } from "@nirholas/pump-sdk";
// These are the fields on every BondingCurve account:
interface BondingCurve {
virtualTokenReserves: BN; // Virtual token pool (determines price)
virtualSolReserves: BN; // Virtual SOL pool (determines price)
realTokenReserves: BN; // Real tokens remaining for sale
realSolReserves: BN; // Real SOL collected
tokenTotalSupply: BN; // Total supply of the token
complete: boolean; // True = graduated to AMM
creator: PublicKey; // Token creator address
isMayhemMode: boolean; // Whether Mayhem mode is active
}Given a SOL amount, how many tokens will you receive?
import { getBuyTokenAmountFromSolAmount, OnlinePumpSdk } from "@nirholas/pump-sdk";
import BN from "bn.js";
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const onlineSdk = new OnlinePumpSdk(connection);
const mint = new PublicKey("YOUR_MINT");
const global = await onlineSdk.fetchGlobal();
const feeConfig = await onlineSdk.fetchFeeConfig();
const bondingCurve = await onlineSdk.fetchBondingCurve(mint);
// How many tokens for 1 SOL?
const solAmount = new BN(1_000_000_000); // 1 SOL in lamports
const tokensOut = getBuyTokenAmountFromSolAmount({
global,
feeConfig,
mintSupply: bondingCurve.tokenTotalSupply,
bondingCurve,
amount: solAmount,
});
console.log(`1 SOL buys ${tokensOut.toString()} tokens`);Given a token amount, how much SOL will you receive?
import { getSellSolAmountFromTokenAmount } from "@nirholas/pump-sdk";
const tokenAmount = new BN("1000000000"); // Tokens to sell
const solOut = getSellSolAmountFromTokenAmount({
global,
feeConfig,
mintSupply: bondingCurve.tokenTotalSupply,
bondingCurve,
amount: tokenAmount,
});
console.log(`Selling tokens → ${solOut.toNumber() / 1e9} SOL`);How much SOL to buy a specific number of tokens?
import { getBuySolAmountFromTokenAmount } from "@nirholas/pump-sdk";
const wantTokens = new BN("5000000000"); // Want this many tokens
const solCost = getBuySolAmountFromTokenAmount({
global,
feeConfig,
mintSupply: bondingCurve.tokenTotalSupply,
bondingCurve,
amount: wantTokens,
});
console.log(`Cost to buy tokens: ${solCost.toNumber() / 1e9} SOL`);import { bondingCurveMarketCap } from "@nirholas/pump-sdk";
const marketCap = bondingCurveMarketCap({
mintSupply: bondingCurve.tokenTotalSupply,
virtualSolReserves: bondingCurve.virtualSolReserves,
virtualTokenReserves: bondingCurve.virtualTokenReserves,
});
console.log("Market cap:", marketCap.toString(), "lamports");
console.log("Market cap:", marketCap.toNumber() / 1e9, "SOL");Generate price points across the bonding curve to plot a chart:
import { newBondingCurve, getBuyTokenAmountFromSolAmount } from "@nirholas/pump-sdk";
function generatePriceCurve(global: Global, feeConfig: FeeConfig, steps: number = 20) {
const curve = newBondingCurve(global);
const totalRealTokens = curve.realTokenReserves;
const stepSize = totalRealTokens.divn(steps);
const points: { tokensBought: string; price: string; marketCap: string }[] = [];
for (let i = 0; i <= steps; i++) {
const tokensIn = stepSize.muln(i);
// Simulate the curve state after buying `tokensIn` tokens
const virtualTokens = curve.virtualTokenReserves.sub(tokensIn);
const virtualSol = curve.virtualSolReserves
.mul(curve.virtualTokenReserves)
.div(virtualTokens);
const price = virtualSol.toNumber() / virtualTokens.toNumber();
points.push({
tokensBought: tokensIn.toString(),
price: price.toFixed(12),
marketCap: (price * curve.tokenTotalSupply.toNumber()).toFixed(0),
});
}
return points;
}
const pricePoints = generatePriceCurve(global, feeConfig);
console.table(pricePoints);- All amounts use
BN(bn.js) — never JavaScriptnumberfor financial math - SOL amounts are in lamports — 1 SOL = 1,000,000,000 lamports
complete === truemeans the token graduated to PumpAMM — bonding curve is closedvirtualTokenReserves === 0means fully migrated- Fees are subtracted from the SOL amount before the swap calculation