Introduction
Pumpfun amm recently launched (at the time of writing) and it is pumpfuns take on an automated market maker. As a developer of a solana pumpfun bot, one of the key challenges of building transactions is figuring out how the prices are calculated. This post will explain how to calculate the price of a pumpfun amm token so you can use it in your transactions.
Maths
All of the tokens/amounts are expressed in lamports (in case of solana) or decimals (in case of other tokens).
If you are not familiar with the concept of lamports, it is the smallest unit of solana. 1 sol = 1_000_000_000 lamports. If you are buying tokens with solana, then your quote amount in lamports is the amount of solana you are sending to the pool.
⚠️ Note: When I'm using sol, I actually mean wrapped sol (wsol) which is what the new pumpfun amm uses. So you will need to wrap your solana before sending it to the pool.
Pumpfun AMM Token Price Calculation
Definitions
1️⃣ Let lpFeeBps be the liquidity provider fee in basis points.
2️⃣ Let protocolFeeBps be the protocol fee in basis points.
3️⃣ Let QuoteAmountIn be the amount of quote tokens being swapped. If you are buying with sol, this would for example be the amount of sol you are sending in lamports.
4️⃣ Let PoolBaseTokenReserves be the reserves of the base token in the pool.
5️⃣ Let PoolQuoteTokenReserves be the reserves of the quote token in the pool.
How to find lpFeeBps and protocolFeeBps
Those are fixed values for most of the time, at time of writing the fees are as following, and will likely stay like this. Make sure to check it out once a while if you will be hardcoding them.
To find it, go to solscan and find a PumpFun Buy IX.
Example TX
Check out the following image to see where to find them:
Calculations
-
Total Fee Basis Points:
totalFeeBps = lpFeeBps + protocolFeeBps
This step calculates the total fee (in basis points) by summing the liquidity provider fee and the protocol fee. Basis points are used to represent percentages, where 1 basis point equals 0.01%.
-
Denominator for Effective Quote Calculation:
denominator = 10000 + totalFeeBps
The denominator is calculated by adding the total fee (in basis points) to 10,000 (the base value representing 100%). This value will be used to adjust the quote amount to account for fees.
-
Effective Quote Amount:
effectiveQuote = (QuoteAmountIn * 10000) / denominator
The effective quote amount is the adjusted amount of quote tokens after accounting for the fees. This is done by scaling the input quote amount by 10,000 and dividing it by the denominator calculated in the previous step.
-
Base Tokens Received:
numerator = PoolBaseTokenReserves * effectiveQuote denominatorEffective = PoolQuoteTokenReserves + effectiveQuote
The numerator represents the product of the base token reserves and the effective quote amount. The denominatorEffective is the sum of the quote token reserves and the effective quote amount. These values are used to calculate the amount of base tokens received.
baseAmountOut = numerator / denominatorEffective
The final amount of base tokens received (
baseAmountOut
) is calculated by dividing the numerator by the denominatorEffective. This represents the number of base tokens you will receive for the given input quote tokens.
Implementation
javascript 🦕
this javascript implementation is from the pumpfun amm sdk on npm : source code
// 1) Calculate total fee basis points and denominator
const totalFeeBps = lpFeeBps.add(protocolFeeBps);
const denominator = new BN(10_000).add(totalFeeBps);
// 2) Calculate effective quote amount
const effectiveQuote = quote.mul(new BN(10_000)).div(denominator);
// 3) Calculate the base tokens received using effectiveQuote
// base_amount_out = floor(base_reserve * effectiveQuote / (quote_reserve + effectiveQuote))
const numerator = baseReserve.mul(effectiveQuote);
const denominatorEffective = quoteReserve.add(effectiveQuote);
if (denominatorEffective.isZero()) {
throw new Error("Pool would be depleted; denominator is zero.");
}
const baseAmountOut = numerator.div(denominatorEffective);
// 4) Calculate maxQuote with slippage
// If slippage=1 => factor = (1 + 1/100) = 1.01
const precision = new BN(1_000_000_000); // For slippage calculations
const slippageFactorFloat = (1 + slippage / 100) * 1_000_000_000;
const slippageFactor = new BN(Math.floor(slippageFactorFloat));
// maxQuote = quote * slippageFactor / 1e9
const maxQuote = quote.mul(slippageFactor).div(precision);
golang 🦫
this golang implementation was done by me. which is a port of the javascript/typescript code above. I have an ammEvent struct which has the following fields, I extract this data from the transaction logs: This just the buy event which is found in the logs.
type AMMBuyEvent struct {
Identifier [8]byte
Timestamp int64
Base_amount_out uint64
Max_quote_amount_in uint64
User_base_token_reserves uint64
User_quote_token_reserves uint64
Pool_base_token_reserves uint64
Pool_quote_token_reserves uint64
Quote_amount_in uint64
Lp_fee_basis_points uint64
Lp_fee uint64
Protocol_fee_basis_points uint64
Protocol_fee uint64
Quote_amount_in_with_lp_fee uint64
User_quote_amount_in uint64
Pool solana.PublicKey
User solana.PublicKey
User_base_token_account solana.PublicKey
User_quote_token_account solana.PublicKey
Protocol_fee_recipient solana.PublicKey
Protocol_fee_recipient_token_account solana.PublicKey
}
And this is the golang code to calculate the base amount out:
// Calculate total fee basis points and denominator
lpFeeBps := big.NewInt(int64(ammEvent.Lp_fee_basis_points))
protocolFeeBps := big.NewInt(int64(ammEvent.Protocol_fee_basis_points))
totalFeeBps := new(big.Int).Add(lpFeeBps, protocolFeeBps)
denominator := new(big.Int).Add(big.NewInt(10000), totalFeeBps)
// Calculate effective quote amount
effectiveQuote := new(big.Int).Mul(big.NewInt(int64(QuoteAmountIn)), big.NewInt(10000))
effectiveQuote = effectiveQuote.Div(effectiveQuote, denominator)
// Calculate the base tokens received using effectiveQuote
numerator := new(big.Int).Mul(big.NewInt(int64(ammEvent.Pool_base_token_reserves)), effectiveQuote)
denominatorEffective := new(big.Int).Add(big.NewInt(int64(ammEvent.Pool_quote_token_reserves)), effectiveQuote)
if denominatorEffective.Cmp(big.NewInt(0)) == 0 {
return nil, errors.New("Pool would be depleted; denominator is zero.")
}
baseAmountOut := new(big.Int).Div(numerator, denominatorEffective).Uint64()
Conclusion
This is certainly not the only calculation you will need to do when building a pumpfun bot. But I just wrote this as lots of people were asking how to calculate the price of a pumpfun amm token.