UNPKG

@pump-fun/pump-swap-sdk

Version:

Official SDK for interacting with Pump Swap AMM protocol on Solana

111 lines (106 loc) 4.05 kB
// src/sdk/sell.ts import BN3 from "bn.js"; // src/sdk/util.ts import BN2 from "bn.js"; import { AnchorProvider, Program } from "@coral-xyz/anchor"; // src/sdk/pda.ts import { PublicKey } from "@solana/web3.js"; import BN from "bn.js"; import { getAssociatedTokenAddressSync, NATIVE_MINT, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; var PUMP_AMM_PROGRAM_ID = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"; var PUMP_AMM_PROGRAM_ID_PUBKEY = new PublicKey(PUMP_AMM_PROGRAM_ID); var PUMP_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; var PUMP_PROGRAM_ID_PUBKEY = new PublicKey(PUMP_PROGRAM_ID); var PUMP_MINT = new PublicKey( "pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn" ); // src/sdk/util.ts function ceilDiv(a, b) { if (b.isZero()) { throw new Error("Cannot divide by zero."); } return a.add(b.subn(1)).div(b); } function fee(amount, basisPoints) { return ceilDiv(amount.mul(basisPoints), new BN2(1e4)); } // src/sdk/sell.ts import { PublicKey as PublicKey2 } from "@solana/web3.js"; function sellBaseInputInternal(base, slippage, baseReserve, quoteReserve, globalConfig, coinCreator) { if (baseReserve.isZero() || quoteReserve.isZero()) { throw new Error( "Invalid input: 'baseReserve' or 'quoteReserve' cannot be zero." ); } const quoteAmountOut = quoteReserve.mul(base).div(baseReserve.add(base)); const lpFee = fee(quoteAmountOut, globalConfig.lpFeeBasisPoints); const protocolFee = fee(quoteAmountOut, globalConfig.protocolFeeBasisPoints); const coinCreatorFee = PublicKey2.default.equals(coinCreator) ? new BN3(0) : fee(quoteAmountOut, globalConfig.coinCreatorFeeBasisPoints); const finalQuote = quoteAmountOut.sub(lpFee).sub(protocolFee).sub(coinCreatorFee); if (finalQuote.isNeg()) { throw new Error("Fees exceed total output; final quote is negative."); } const precision = new BN3(1e9); const slippageFactorFloat = (1 - slippage / 100) * 1e9; const slippageFactor = new BN3(Math.floor(slippageFactorFloat)); const minQuote = finalQuote.mul(slippageFactor).div(precision); return { uiQuote: finalQuote, // actual tokens user receives after fees minQuote, // minimum acceptable tokens after applying slippage internalQuoteAmountOut: quoteAmountOut }; } var MAX_FEE_BASIS_POINTS = new BN3(1e4); function calculateQuoteAmountOut(userQuoteAmountOut, lpFeeBasisPoints, protocolFeeBasisPoints, coinCreatorFeeBasisPoints) { const totalFeeBasisPoints = lpFeeBasisPoints.add(protocolFeeBasisPoints).add(coinCreatorFeeBasisPoints); const denominator = MAX_FEE_BASIS_POINTS.sub(totalFeeBasisPoints); return ceilDiv(userQuoteAmountOut.mul(MAX_FEE_BASIS_POINTS), denominator); } function sellQuoteInputInternal(quote, slippage, baseReserve, quoteReserve, globalConfig, coinCreator) { if (baseReserve.isZero() || quoteReserve.isZero()) { throw new Error( "Invalid input: 'baseReserve' or 'quoteReserve' cannot be zero." ); } if (quote.gt(quoteReserve)) { throw new Error( "Cannot receive more quote tokens than the pool quote reserves." ); } const rawQuote = calculateQuoteAmountOut( quote, globalConfig.lpFeeBasisPoints, globalConfig.protocolFeeBasisPoints, PublicKey2.default.equals(coinCreator) ? new BN3(0) : globalConfig.coinCreatorFeeBasisPoints ); if (rawQuote.gte(quoteReserve)) { throw new Error( "Invalid input: Desired quote amount exceeds available reserve." ); } const baseAmountIn = ceilDiv( baseReserve.mul(rawQuote), quoteReserve.sub(rawQuote) ); const precision = new BN3(1e9); const slippageFactorFloat = (1 - slippage / 100) * 1e9; const slippageFactor = new BN3(Math.floor(slippageFactorFloat)); const minQuote = quote.mul(slippageFactor).div(precision); return { internalRawQuote: rawQuote, base: baseAmountIn, // amount of base tokens required to get the desired quote minQuote // minimum acceptable tokens after applying slippage }; } export { sellBaseInputInternal, sellQuoteInputInternal };