npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pump-fun/pump-sdk

v4.1.0

Published

Pump Bonding Curve SDK

Readme

Pump SDK

Official Pump program SDK

Updates

v3 bonding-curve trades, fee buckets and sweeps

Tracks pump-programs-monorepo PR #60. The v1 / v2 trades keep working unchanged.

Also tracks PR #61 (stacked on #55): the same v3 / v2 changes plus pump coins as quote mints, the post-completion buy and multi-hop routes.

  • Pump coins as create_v2 quotes. A pump coin listed on neither Global nor quote control can quote a new coin. OnlinePumpSdk.resolveQuoteMint resolves it (source: "pumpCoin"). Pass its pumpQuote.accounts to createV2Instruction / createV2AndBuyV2Instructions as pumpQuote, and its pumpQuote.curve to the quote functions. The new coin's reserves are derived from what a standard launch's raise buys up the quote coin's whole quote chain, every coin priced live (programs #64; a raise past a trading coin's remaining supply completes it and buys on from its pool-to-be, as buy_v3 would); fetchPumpQuote walks the chain and pumpQuote.accounts.chain carries one account group per coin below the quote coin. Its depth is the quote coin's plus one, capped by Global.maxCurveDepth (setMaxCurveDepthInstruction; 0 disables the path) and the program's MAX_CURVE_DEPTH (5). A deep chain of migrated coins needs a v0 transaction with a lookup table. Refusals map to typed errors (CurveDepthExceededError, QuoteBondingCurveNotEligibleError, QuoteCurveAwaitingMigrationError, QuoteReservesOutOfRangeError).

  • Post-completion buy. A buy_v3 / buy_exact_quote_in_v3 past the remaining supply completes the curve and buys the rest from the pool the migration will create. Quote it with getBuyV3QuoteAmountFromTokenAmount / getBuyV3TokenAmountFromQuoteAmount, which need the curve's base token balance (fetchBuyState returns it as curveBaseTokenBalance, read under the coin's real token program). On a complete curve they return 0. partialFill now only matters on mayhem curves, where there is no post-completion leg. New PostCompleteBuyEvent (decodePostCompleteBuyEvent).

  • Multi-hop routes (pump-amm multi_hop_swap): OnlinePumpSdk.resolveMultiHopRoute(path, side) picks each hop's venue, simulateMultiHopSwap returns the amount out, and PumpSdk.multiHopSwapInstructions builds the swap (wrapping SOL in, closing the WSOL account after, creating the buyback ATA). SOL-quoted curves can be hops too, at the route's SOL end (pump-programs-monorepo #63): SOL moves as lamports between the wallet and the curve, so the user's WSOL account there is only a placeholder (created, not funded) and a buy needs amountIn plus rent in the wallet; mayhem curves are refused. Routes are all buys or all sells. The buyback ATA is in the user's currency. More than three hops needs a v0 transaction with a lookup table; pass it to simulateMultiHopSwap as addressLookupTables too.

  • Layouts. BondingCurve gains depth, initialVirtualQuoteReserves, postCompleteBaseOut and postCompleteQuoteIn (BONDING_CURVE_SIZE / BONDING_CURVE_NEW_SIZE 166). Global gains maxCurveDepth (GLOBAL_SIZE 1088; run extend_account on Global after the upgrade). CreateEvent gains depth. Older layouts still decode, with zeros.

  • Fix: pump-amm's GlobalConfig is now the right PDA (global_config) in adminCtoInstruction and sweepPoolCreatorFeeInstruction. The exported AMM_GLOBAL_PDA now derives it too and is deprecated in favour of pump-swap-sdk's GLOBAL_CONFIG_PDA.

  • New trades: buy_v3, buy_exact_quote_in_v3, sell_v3. Use buyV3Instructions, buyExactQuoteInV3Instructions and sellV3Instructions, or their get*V3InstructionRaw versions. They take 17 accounts. Within the remaining supply prices and fees are the same as v2; quote v3 buys with getBuyV3QuoteAmountFromTokenAmount / getBuyV3TokenAmountFromQuoteAmount, which also price a buy past it (see the post-completion buy above). Only the buyback slice of the protocol fee is paid in the trade. The rest of the protocol fee and the creator fee stay on the curve (BondingCurve.protocolFees / creatorFee) until a sweep pays them out. Cashback coins are refused (6094, CashbackCoinNotSupportedError); trade them with v2. See Trading with v3.

  • One buyback account. On a SOL curve it is a listed Global.buybackFeeRecipients wallet (random by default). On a token quote it is the first listed wallet's quote ATA, 5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD (override with buybackFeeRecipient). The program refuses a missing ATA and never creates it, so the v3 builders and multiHopSwapInstructions create it idempotently first; the raw builders do not.

  • Sweeps. sweepProtocolFeeInstruction and sweepCreatorFeeInstruction are permissionless payouts. So is sweepPoolCreatorFeeInstruction (pump-amm), for creator fees that the pump-amm v2 pool trades leave in the pool. An un-swept creator bucket blocks distribute_creator_fees(_v2), admin_cto, fee-sharing creation and update_fee_shares(_v2) (pump 6095 / pump-amm 6081 CreatorFeesNotSwept, pump-fees 6033 PoolCreatorFeesNotSwept for a pool bucket on update_fee_shares(_v2)). Put the sweep first in the same transaction. OnlinePumpSdk.adminCtoInstructions and buildDistributeCreatorFeesInstructions do it for you whenever a bucket is nonzero. The latter needs a payer (even for a SOL coin) only when the curve bucket is nonzero, leaves the optional pool sweep out without one, and reports the sweeps as sweepCount; a list too large for one transaction goes in a v0 transaction with a lookup table. getMinimumDistributableFee counts a SOL curve's un-swept bucket as distributable. The pool sweep pays the vault of the pool's own coin_creator. Sweeps refuse the zero key as a destination, and getFeeRecipient skips unset slots.

  • update_fee_shares(_v2) on a complete curve takes the coin's canonical pool as an extra account after the shareholders (and after their quote ATAs on v2) to check the pool's creator bucket. updateFeeShares / updateFeeSharesV2 append it unless bondingCurveComplete: false (a live curve ignores it; leaving it out saves 33 bytes): the WSOL pool on v1, the pool of quoteMint on v2 (it must be the curve's quote). It doesn't have to exist yet. Instructions built by older SDK versions leave it out and fail on a complete curve.

  • Accounts and events. BondingCurve gains creatorFee / protocolFees (BONDING_CURVE_SIZE 125 → 141, 166 with #61; shorter curves decode with zeros). QuoteControl gains reservesAdmin, carved out of its reserved area. New decoders: decodeSweepBondingCurveFeeEvent and decodeSweepPoolFeeEventAmm. TradeEventBc, BuyEventAmm and SellEventAmm gain creatorFeeUnclaimed: the curve's or pool's creator bucket after the trade, i.e. creator fees not swept yet. Events emitted before the field existed decode it as zero. The legacy buy, buy_v2 and buy_exact_* instructions gained a trailing partial_fill argument, which the builders send as unset.

  • Not included in this SDK: pump-amm's buy_v2 / sell_v2 pool trades and the pool protocol sweep, which live in @pump-fun/pump-swap-sdk. Creator-vault balances and collects don't see fees that are still in a bucket; sweep the coin first. They also cover only listed quote mints: pass pump-coin quotes as extraQuoteMints.

Holder-reward coins, one CTO instruction, cashback retired (create_v2)

Trading instructions are unchanged and do not require an upgrade. What changed on create_v2:

  • Holder-reward coins. create_v2 takes a trailing is_holder_reward argument (OptionBool, EOF-tolerant: older instruction data still decodes). Pass holderReward: true to createV2Instruction / createV2AndBuyV2Instructions / createV2AndBuyInstructions: the program ignores creator and makes the coin's holderRewardsPda(mint) the creator, so every creator fee accrues to that PDA's vault and is paid out to the coin's holders instead of a wallet. Permanent. See Holder-reward coins.
  • Cashback is deprecated. create_v2 rejects is_cashback_enabled = true (6082 CashbackDeprecated); the create-and-buy builders throw CashbackDeprecatedError up front. Existing cashback coins are unchanged: trades still route the creator fee to the buyer and claimCashbackInstruction / claimCashbackV2Instruction still claim it.
  • One CTO instruction. admin_set_creator, admin_set_all_coin_creators, admin_set_creator_fee_editable and set_creator_fee_bps (and pump-fees reset_fee_sharing_config*) are gone; admin_cto replaces them all and drives the pump-amm pool and the pump-fees sharing config itself. A configured creator fee changes only through it. See Changing the rate later: only through a CTO.
  • Accounts and events. BondingCurve gains isHolderReward (BONDING_CURVE_SIZE 124 → 125), Global gains holderRewardClaimAuthority / isHolderRewardEnabled (GLOBAL_SIZE 1054 → 1087); CreateEvent gains isHolderReward, TradeEvent (and pump-amm BuyEvent / SellEvent) gain holderRewardsBps / holderRewards alongside the unchanged creatorFee*. Removed builders: setCreatorFeeBpsInstruction, adminSetCreatorFeeEditableInstruction, OnlinePumpSdk.adminSetCoinCreatorInstructions / adminSetCreatorFeeEditableInstructions / setCreatorFeeBpsInstructions; removed decoders and types: AdminSetCreatorEventBc, AdminSetCoinCreatorEventAmm, SetCreatorFeeBpsEvent, AdminSetCreatorFeeEditableEvent.

One-Time Creator Reward Distribution Policy

This update only affects fee-sharing configuration. Trading instructions are unchanged and do not require an upgrade.

TLDR: After the first configuration, reward distribution is locked and cannot be changed.

What changed:

  • Reward distribution can be configured only once.
  • You can configure it using either updateFeeShares or updateSharingConfigWithSocialRecipients.
  • After it is configured, it is locked and cannot be changed again.

What did not change:

  • Buy and sell instructions are unchanged.

Migration/compatibility notes:

  • Reward distributions created before this policy are treated as final (locked).
  • RevokeFeeSharingAuthority and TransferFeeSharingAuthority are no longer supported.
  • If you are unsure whether a reward distribution is still editable, call isSharingConfigEditable.
import { isSharingConfigEditable } from "@pump-fun/pump-sdk";

Usage

const connection = new Connection(
    "https://api.devnet.solana.com",
    "confirmed",
);
const sdk = new PumpSdk(connection);

Coin creation

const mint = PublicKey.unique();
const creator = PublicKey.unique();
const user = PublicKey.unique();

const instruction = await sdk.createInstruction({
    mint,
    name: "name",
    symbol: "symbol",
    uri: "uri",
    creator,
    user,
});

// or creating and buying instructions in the same tx

const global = await sdk.fetchGlobal();
const solAmount = new BN(0.1 * 10 ** 9); // 0.1 SOL

const instructions = await sdk.createAndBuyInstructions({
    global,
    mint,
    name: "name",
    symbol: "symbol",
    uri: "uri",
    creator,
    user,
    solAmount,
    amount: getBuyTokenAmountFromSolAmount(global, null, solAmount),
});

Buying coins

const mint = PublicKey.unique();
const user = PublicKey.unique();

const global = await sdk.fetchGlobal();
const { bondingCurveAccountInfo, bondingCurve, associatedUserAccountInfo } =
    await sdk.fetchBuyState(mint, user);
const solAmount = new BN(0.1 * 10 ** 9); // 0.1 SOL

const instructions = await sdk.buyInstructions({
    global,
    bondingCurveAccountInfo,
    bondingCurve,
    associatedUserAccountInfo,
    mint,
    user,
    solAmount,
    amount: getBuyTokenAmountFromSolAmount(global, bondingCurve, solAmount),
    slippage: 1,
});

Selling coins

const mint = PublicKey.unique();
const user = PublicKey.unique();

const global = await sdk.fetchGlobal();
const { bondingCurveAccountInfo, bondingCurve } = await sdk.fetchSellState(mint, user);
const amount = new BN(15_828);

const instructions = await sdk.sellInstructions({
    global,
    bondingCurveAccountInfo,
    bondingCurve,
    mint,
    user,
    amount,
    solAmount: getSellSolAmountFromTokenAmount(global, bondingCurve, amount),
    slippage: 1,
});

Trading with v3

The state from fetchBuyState / fetchSellState works as is, given the coin's token program: they default to SPL Token while the v3 builders default to Token-2022, so pass it to both (TOKEN_2022_PROGRAM_ID for create_v2 coins). Quote buys with the v3 functions, which also price the post-completion leg when the buy crosses the remaining supply:

const [global, feeConfig] = await Promise.all([
    onlineSdk.fetchGlobal(),
    onlineSdk.fetchFeeConfig(),
]);
const { bondingCurve, associatedUserAccountInfo, quoteTokenProgram, curveBaseTokenBalance } =
    await onlineSdk.fetchBuyState(mint, user, TOKEN_2022_PROGRAM_ID);
const quoteAmount = new BN(0.1 * 10 ** 9); // spend at most 0.1 SOL, fees included

const instructions = await PUMP_SDK.buyExactQuoteInV3Instructions({
    bondingCurve,
    associatedUserAccountInfo,
    mint,
    user,
    quoteAmount,
    amount: getBuyV3TokenAmountFromQuoteAmount({
        global,
        feeConfig,
        mintSupply: bondingCurve.tokenTotalSupply,
        bondingCurve,
        amount: quoteAmount,
        curveBaseTokenBalance,
    }),
    slippage: 1,
    quoteTokenProgram,
});

// sellV3Instructions({ bondingCurve, mint, user, amount, quoteAmount, slippage, quoteTokenProgram })
// buyV3Instructions({ bondingCurve, ..., amount, quoteAmount: getBuyV3QuoteAmountFromTokenAmount(...), slippage })

The fees accrue on the curve. Anyone can pay them out:

const sweepCreator = await PUMP_SDK.sweepCreatorFeeInstruction({
    payer,
    mint,
    creator: bondingCurve.creator,
    quoteMint: bondingCurve.quoteMint,
    quoteTokenProgram,
});
const sweepProtocol = await PUMP_SDK.sweepProtocolFeeInstruction({
    payer,
    mint,
    recipient: getFeeRecipient(global, bondingCurve.isMayhemMode),
    quoteMint: bondingCurve.quoteMint,
    quoteTokenProgram,
});

Quote mints

A bonding curve is quoted in SOL or in a token. The quote mints create_v2 accepts are not a static list: they are SOL, plus the mints whitelisted on Global (USDC on mainnet), plus the mints listed in the on-chain QuoteControl PDA (QUOTE_CONTROL_PDA, managed by an admin, possibly not initialized yet). Read the set from chain instead of hardcoding it:

import { OnlinePumpSdk } from "@pump-fun/pump-sdk";

const onlineSdk = new OnlinePumpSdk(connection);

// SOL first (reported as NATIVE_MINT), then the Global mints, then the
// QuoteControl mints. One RPC round-trip.
const supported = await onlineSdk.fetchSupportedQuoteMints();
// [{ mint, source: "sol" | "global" | "quoteControl", initialVirtualQuoteReserves }]
// (pump coins are not enumerated: any pump coin may quote once
// Global.maxCurveDepth allows it)

// One mint, with what the builders need for it. A pump coin listed nowhere
// resolves as `source: "pumpCoin"` (see the Updates section); a mint that is
// neither listed nor a pump coin throws UnsupportedQuoteMintError, and a
// refused pump coin throws the matching typed error (CurveDepthExceededError,
// ...).
const usdc = await onlineSdk.resolveQuoteMint(USDC_MINT);
usdc.quoteTokenProgram; // the program that owns the mint: TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID
usdc.decimals;
usdc.initialVirtualQuoteReserves; // what a new curve quoted in it starts from

// Or just the token program (no RPC call for SOL).
const quoteTokenProgram = await onlineSdk.fetchQuoteTokenProgram(quoteMint);

The quote token program

Every quote-side account a trade touches (the fee recipients', the bonding curve's, the user's, the creator vault's and the cashback accumulator's token accounts) is an ATA derived with the program that owns the quote mint, and that program may be SPL Token or Token-2022. Every builder that takes a quoteMint therefore also takes a quoteTokenProgram. The default, TOKEN_PROGRAM_ID, is right for SOL and USDC only; for anything else pass the mint's owner, from fetchQuoteTokenProgram / resolveQuoteMint, or from fetchBuyState / fetchSellState, which return the curve's quoteMint and quoteTokenProgram alongside the curve (pass the quote mint as the optional last argument when you already know it to save a round-trip).

Creating a coin quoted in a token

createV2AndBuyV2Instructions builds the create, the user's token account and the first buy, all agreeing on the quote. Token-quoted creates and first buys are heavy (roughly 200-240k CU each), so set an explicit compute budget: about 500k for create + buy, 250-300k for a standalone buy_v2 / sell_v2 on a Token-2022 quote.

import { ComputeBudgetProgram } from "@solana/web3.js";
import { getBuyTokenAmountFromSolAmount, PUMP_SDK } from "@pump-fun/pump-sdk";

const global = await onlineSdk.fetchGlobal();
const feeConfig = await onlineSdk.fetchFeeConfig();
const quoteControl = await onlineSdk.fetchQuoteControl(); // null until initialized

// USDC: whitelisted on Global, SPL Token.
const quoteAmount = new BN(10 * 10 ** 6); // 10 USDC
const usdcInstructions = [
  ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 }),
  ...(await PUMP_SDK.createV2AndBuyV2Instructions({
    global,
    mint,
    name,
    symbol,
    uri,
    creator,
    user,
    quoteMint: USDC_MINT,
    quoteTokenProgram: TOKEN_PROGRAM_ID,
    quoteAmount,
    amount: getBuyTokenAmountFromSolAmount({
      global,
      feeConfig,
      mintSupply: null,
      bondingCurve: null,
      amount: quoteAmount,
      quoteMint: USDC_MINT,
      quoteControl,
    }),
    mayhemMode: false,
  })),
];

// A Token-2022 quote admitted through QuoteControl.
const quote = await onlineSdk.resolveQuoteMint(XSTOCK_MINT);
const token2022Instructions = [
  ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 }),
  ...(await PUMP_SDK.createV2AndBuyV2Instructions({
    global,
    mint,
    name,
    symbol,
    uri,
    creator,
    user,
    quoteMint: quote.mint,
    quoteTokenProgram: quote.quoteTokenProgram, // TOKEN_2022_PROGRAM_ID
    quoteAmount,
    amount: getBuyTokenAmountFromSolAmount({
      global,
      feeConfig,
      mintSupply: null,
      bondingCurve: null,
      amount: quoteAmount,
      quoteMint: quote.mint,
      quoteControl, // seeds the new curve from the QuoteControl entry
    }),
    mayhemMode: false, // a quote-control-only mint cannot be a mayhem coin (6071)
  })),
];

Under the hood a non-SOL create_v2 carries four remaining accounts, in this order: the quote mint, the bonding curve's quote ATA (writable; the program creates it), the quote token program, and the QuoteControl PDA. The program reads the PDA only for a mint Global does not whitelist, so the SDK always appends it; the program deployed before quote control ignores a fourth account.

Fee schedule by quote mint

pump-fees selects a bonding curve's (and its canonical pool's) fee schedule from the quote mint, and so does the SDK's quote math (computeFeesBps, getBuyTokenAmountFromSolAmount, ... via selectCurveFeeSchedule):

| Quote mint | Schedule | | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | SOL-like: the zero key, WSOL So111…112, the Token-2022 native mint 9pan9… (SOL_LIKE_QUOTE_MINTS) | market-cap tier from FeeConfig.feeTiers | | A listed stable: mainnet USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (STABLE_QUOTE_MINTS, hardcoded on chain) | market-cap tier from FeeConfig.stableFeeTiers | | Anything else (devnet USDC included) | FeeConfig.exoticFlatFees, or flatFees while that schedule is unset (all zero) |

Token-2022 quote accounts

ATAs of a Token-2022 quote mint carry extensions, so they are 170-182 bytes (175 for the xStock extension profile), never the 165 bytes of an SPL Token account. Do not size or parse quote token accounts assuming 165 bytes; unpackAccount from @solana/spl-token handles both.

Errors

create_v2 checks the quote in this order, so the first mismatch is what you see:

  • 6064 InvalidQuoteTokenProgram: remaining account [2] is not SPL Token or Token-2022.
  • 6063 UnsupportedQuoteMint: the Token-2022 native mint; or, when Global does not whitelist the mint, a missing remaining account [3] (a quote-control mint sent with only three remaining accounts) or a mint QuoteControl does not list.
  • 6075 InvalidQuoteControl: Global does not whitelist the mint and remaining account [3] is present but is not the canonical, pump-owned, well-formed QuoteControl PDA.
  • 6063 UnsupportedQuoteMint again, after the list lookup: the quote token program is not the mint's owner, or a Token-2022 mint with an extension outside the xStock operable set.
  • 6065 InvalidAssociatedQuoteBondingCurve: the program is right but remaining account [1] is not the bonding curve's ATA under it.
  • 6071 MayhemModeQuoteMintNotAllowed: mayhemMode with a mint admitted only through QuoteControl.

Managing the quote-control list (admin)

// Permissionless, once: anyone can create the PDA (no admin, empty list).
await PUMP_SDK.initializeQuoteControlInstruction({ user });

// Global.authority assigns the admin (the zero key revokes it).
await onlineSdk.adminSetQuoteControlAdminInstruction({ newAdmin }); // authority defaults to Global.authority

// QuoteControl.admin or Global.authority lists / de-lists mints. The reserves
// are what a new curve quoted in the mint starts from, in the mint's base units.
await onlineSdk.adminAddQuoteControlMintInstruction({
  quoteMint,
  initialVirtualQuoteReserves: new BN(4_292_000_000),
  authority: quoteControlAdmin, // optional; defaults to Global.authority
});
await onlineSdk.adminRemoveQuoteControlMintInstruction({ quoteMint });

// FeeConfig.admin sets the flat schedule exotic quotes pay.
await onlineSdk.adminSetExoticFlatFeesInstruction({
  exoticFlatFees: { lpFeeBps: new BN(0), protocolFeeBps: new BN(300), creatorFeeBps: new BN(25) },
});

The offline PumpSdk has the same builders with explicit signers (setQuoteControlAdminInstruction, addQuoteControlMintInstruction, removeQuoteControlMintInstruction, setExoticFlatFeesInstruction).

Configurable creator fee

A coin can carry its own creator fee rate instead of the pump-fees schedule's. BondingCurve.creatorFeeBps is that rate in basis points, and zero means "not configured": the schedule's creator rate for the coin's quote mint applies (see Fee schedule by quote mint). While Global.creatorFeeConfigurable is on, a nonzero rate replaces the schedule's creator rate on every trade of that coin; the protocol rate is untouched. With the gate off, configured rates are neither read nor accepted (a kill switch). A rate must be within 1..=Global.maxConfigurableCreatorFeeBps, and only a coin quoted through QuoteControl stores one: on a SOL or USDC quote the create-time value is ignored and a CTO refuses it (6091). The SDK's quote math applies the stored rate by itself: computeFeesBps, getFee, getBuyTokenAmountFromSolAmount, getBuySolAmountFromTokenAmount and getSellSolAmountFromTokenAmount read bondingCurve.creatorFeeBps and global.creatorFeeConfigurable, so an unconfigured coin quotes exactly as before.

Creating a coin with its own creator fee

Pass creatorFeeBps to createV2Instruction, createV2AndBuyV2Instructions or createV2AndBuyInstructions. It becomes create_v2's creator_fee_bps argument, which the SDK always sends (zero when unset) right before the trailing is_holder_reward byte. Quote the first buy with the same rate so it covers the fees the program charges:

const creatorFeeBps = new BN(250); // 2.5%
const quoteAmount = new BN(0.1 * 10 ** 9); // 0.1 SOL

const instructions = await PUMP_SDK.createV2AndBuyV2Instructions({
  global,
  mint,
  name,
  symbol,
  uri,
  creator,
  user,
  quoteAmount,
  amount: getBuyTokenAmountFromSolAmount({
    global,
    feeConfig,
    mintSupply: null,
    bondingCurve: null,
    amount: quoteAmount,
    quoteMint: NATIVE_MINT,
    creatorFeeBps, // the first buy pays the configured rate
  }),
  mayhemMode: false,
  creatorFeeBps,
});

createV2Instruction encodes whatever it is given; the program rejects a nonzero rate while the gate is off (6077 CreatorFeeNotConfigurable) or outside 1..=max (6078 CreatorFeeBpsOutOfRange), and any cashback coin before that (6082 CashbackDeprecated). createV2AndBuyV2Instructions and createV2AndBuyInstructions hold global, so they throw CashbackDeprecatedError, CreatorFeeNotConfigurableError or CreatorFeeBpsOutOfRangeError up front for what the program would reject (a zero or omitted rate always passes).

Changing the rate later: only through a CTO

BondingCurve.canEditCreatorFee is retired: nothing sets or reads it any more. A configured rate is fixed at creation and changes only through a community takeover, admin_cto, signed by Global.adminSetCreatorAuthority. One instruction covers the bonding curve, the coin's canonical pump-amm pool (through admin_cto_pool, when one exists) and its pump-fees SharingConfig (through admin_cto_sharing_config, when the coin is fee-shared); pump signs the two CPIs with its ["pool-authority", mint] PDA, which is the only caller those instructions accept. It replaces admin_set_creator, admin_set_all_coin_creators, admin_set_creator_fee_editable, set_creator_fee_bps and pump-fees reset_fee_sharing_config*.

Two paths, chosen by the arguments:

  • New creator: newCreator set. The outgoing wallet creator is first paid from both vaults; a fee-shared coin keeps its SharingConfig as creator and the config is rewritten to newCreator at 100%.
  • Holder rewards: isHolderReward: true, no newCreator. The coin becomes a holder-reward coin: the creator becomes holderRewardsPda(mint), cashback is cleared, a fee-shared coin's vaults are swept into the PDA's creator vault and its SharingConfig is terminated. Permanent: a later CTO on the coin may only repeat this path to change the rate (6083 HolderRewardCreatorImmutable otherwise), and it needs Global.isHolderRewardEnabled (6084).

creatorFeeBps may be set on either path, only on a quote admitted through QuoteControl (6091 CreatorFeeNotConfigurableForQuote on SOL or USDC), within 1..=Global.maxConfigurableCreatorFeeBps with the gate on, and not on a coin that stays cashback (6080). Mayhem coins cannot be taken over (6088). The instruction needs about ADMIN_CTO_COMPUTE_UNIT_LIMIT (600k) compute units.

// Online: Global and the curve in one round-trip, the signer defaulting to
// Global.adminSetCreatorAuthority, every rule above checked with typed errors
// first. Returns [setComputeUnitLimit(600_000), admin_cto].
const handOver = await onlineSdk.adminCtoInstructions(mint, { newCreator });
const toHolders = await onlineSdk.adminCtoInstructions(mint, {
  isHolderReward: true,
  creatorFeeBps: new BN(250), // exotic quotes only
});

// Offline, with explicit accounts: the creator as the curve stores it (the
// zero key on a legacy curve) and the curve's quote (NATIVE_MINT for SOL).
const instruction = await PUMP_SDK.adminCtoInstruction({
  adminSetCreatorAuthority,
  mint,
  currentCreator: bondingCurve.creator,
  quoteMint: normalizeQuoteMint(bondingCurve.quoteMint),
  quoteTokenProgram, // the program that owns the quote mint
  newCreator,
});

The offline builder marks currentCreator writable unless it is the zero key: the program requires a wallet creator to be passed writable so it can be paid (6092), and the IDL cannot declare it so (a legacy curve's zero-key creator is the system program). AdminCtoEvent (decodeAdminCtoEvent) records both paths: old and new creator, whether the coin is now holder-reward or cashback, old and new rate, whether the sharing config was reset, how much was swept, and whether a pool was updated; pump-amm emits AdminCtoPoolEvent (decodeAdminCtoPoolEventAmm) for the pool side.

Admin: the gate and the ceiling

// Global.authority signs (fetched when omitted).
await onlineSdk.adminUpdateCreatorFeeConfigInstruction({
  creatorFeeConfigurable: true,
  maxConfigurableCreatorFeeBps: new BN(5_000),
});

The program puts no bound on the ceiling. Every sell path subtracts fees with checked arithmetic, so a rate that pushes protocol + creator fees past 100% makes a coin buy-only.

Deploy order and pre-upgrade accounts

The upgrades append fields to BondingCurve (115 → 124 bytes with configurable creator fees, → 125 with holder-reward coins, BONDING_CURVE_SIZE; extend_account still grows a curve to BONDING_CURVE_NEW_SIZE = 151) and to Global (1045 → 1054 → 1087 bytes, GLOBAL_SIZE). The program reads every historical curve length and so does PumpSdk.decodeBondingCurve (a shorter account reads creatorFeeBps = 0, canEditCreatorFee = false, isHolderReward = false). Global is a plain Anchor account: extend_account must run on it right after each program upgrade, and until then decodeGlobal / fetchGlobal read the shorter account with the new fields at their defaults (gate off, holder rewards disabled, the zero key as claim authority). Pre-upgrade curves keep trading, but every instruction that rewrites the whole curve (set_creator, ...) fails on an account that is still 115 bytes until the permissionless extend_account grows it, so prepend PUMP_SDK.extendAccountInstruction({ account, user }) when the account is shorter than the size the instruction writes. admin_cto grows the curve (and, through pump-amm, the pool) itself, the authority paying the rent. update_creator_fee_config and update_holder_reward_config fail on a Global shorter than GLOBAL_SIZE until it is extended.

Events: CreateEvent gains creatorFeeBps and isHolderReward (zero / false from legacy create and in events emitted before the fields existed); decodeCreateEventBc reads every layout: the pre-creator-fee one, the configurable-creator-fee one and the holder-reward one. TradeEvent gains holderRewardsBps / holderRewards, which decodeTradeEventBc reads as zero from older logs. UpdateCreatorFeeConfigEvent, AdminCtoEvent and DistributeFeeToHoldersEvent have decoders on PumpSdk. pump-amm's CreatePoolEvent gains creatorFeeBps, canEditCreatorFee and isHolderReward; decodeCreatePoolEventAmm reads the one- and ten-byte-shorter historical layouts with the missing fields at their defaults, and BuyEvent / SellEvent gain holderRewardsBps / holderRewards (decodeBuyEventAmm / decodeSellEventAmm read zero from older logs); AdminCtoPoolEvent has decodeAdminCtoPoolEventAmm.

Holder-reward coins

A holder-reward coin pays its creator fee to its holders instead of a creator. On chain that is a coin whose creator is the per-mint holderRewardsPda(mint) (["holder-rewards", mint]): BondingCurve.isHolderReward (and Pool.isHolderReward after graduation) is true, and every creator fee accrues to that PDA's creator vault (creatorVaultPda(holderRewardsPda(mint))) exactly as it would for a wallet creator, so the trade paths, the fee math and the creator_vault derivation are unchanged: keep reading bondingCurve.creator. Trade events report the fee twice, in the unchanged creatorFee / creatorFeeBasisPoints and in the new holderRewards / holderRewardsBps (zero on any other coin). A coin becomes holder-reward at creation or through a CTO, and stays so.

const global = await onlineSdk.fetchGlobal();
if (!global.isHolderRewardEnabled) throw new Error("holder-reward coins are off");

// The first buy pays into the PDA's vault: the builders derive it from the
// mint, whatever `creator` says (the program ignores that argument).
const instructions = await PUMP_SDK.createV2AndBuyV2Instructions({
  global,
  mint,
  name,
  symbol,
  uri,
  creator, // ignored by the program on a holder-reward coin
  user,
  quoteAmount,
  amount: getBuyTokenAmountFromSolAmount({
    global,
    feeConfig,
    mintSupply: null,
    bondingCurve: null,
    amount: quoteAmount,
    quoteMint: NATIVE_MINT,
  }),
  mayhemMode: false,
  holderReward: true,
});

// A standalone create.
await PUMP_SDK.createV2Instruction({ mint, name, symbol, uri, creator, user, mayhemMode: false, holderReward: true });

create_v2 needs Global.isHolderRewardEnabled (6084 HolderRewardDisabled); the create-and-buy builders throw HolderRewardDisabledError up front. newBondingCurve(global, quoteMint, quoteControl, creatorFeeBps, isHolderReward) carries the flag for quoting a new curve.

Collecting and paying out

Nothing new is needed to collect: the permissionless collect_creator_fee / collect_creator_fee_v2 (and, after graduation, pump-amm's collect_coin_creator_fee or transfer_creator_fees_to_pump) called with the PDA as creator move the vault onto the PDA (lamports on a SOL quote, the PDA's quote ATA on a token quote). collectCoinCreatorFeeInstructions(holderRewardsPda(mint)) and the V2 / all-quotes variants build them. distribute_fee_to_holders, signed by Global.holderRewardClaimAuthority, then pays amounts[i] from the PDA to holder i:

// Online: the signer from Global, the quote from the curve, the PDA's quote
// ATA passed when it exists (the payout source on a token quote; on a SOL
// quote a parked WSOL account the program sweeps into the PDA first).
const [distribute] = await onlineSdk.distributeFeeToHoldersInstructions(mint, [
  { owner: holderA, amount: new BN(1_000_000) },
  { owner: holderB, amount: new BN(2_500_000) },
]);

// Offline.
await PUMP_SDK.distributeFeeToHoldersInstruction({
  holderRewardClaimAuthority,
  mint,
  quoteMint, // NATIVE_MINT for a SOL coin
  quoteTokenProgram,
  recipients,
  holderRewardsTokenAccount, // omit on a SOL quote with nothing parked
});

Remaining accounts are [owner, owner's quote ATA] per recipient; on a token quote a missing ATA is created (rent paid by the authority). The program refuses a count or ATA mismatch (6085), a SOL payout that would leave the PDA between zero and its rent-exempt minimum (6086; draining it fully is fine) and a token payout without a source account (6087). DistributeFeeToHoldersEvent (decodeDistributeFeeToHoldersEvent) records the mint, the quote (the zero key for SOL), the recipient count and the total.

Admin: the gate and the claim authority

// Global.authority signs (fetched when omitted).
await onlineSdk.adminUpdateHolderRewardConfigInstruction({
  isHolderRewardEnabled: true,
  holderRewardClaimAuthority,
});

Creator fees

const user = PublicKey.unique();

// Getting total accumulated SOL creator fees for both Pump and PumpSwap programs
console.log((await sdk.getCreatorVaultBalanceBothPrograms(user)).toString());

// Collecting SOL creator fees instructions
const instructions = await sdk.collectCoinCreatorFeeInstructions(user);

Creator fees accrue in the coin's quote mint. For coins quoted in a token, collect per mint with collectCoinCreatorFeeV2Instructions(creator, quoteMint, quoteTokenProgram), or sweep every quote mint currently listed on Global or in QuoteControl at once:

// What is waiting, per listed quote mint, in the Pump creator vault and the PumpSwap vault.
const balances = await sdk.getCreatorVaultQuoteBalances(user);

// SOL, then each listed token quote whose vault token account exists. Creates
// the creator's missing quote token accounts (neither program does).
const instructions = await sdk.collectCoinCreatorFeeAllQuotesInstructions(user, feePayer);

// De-listing a mint stops new creates only: curves quoted in it keep accruing
// fees, and the sweep does not know about them. Pass them explicitly.
const all = await sdk.collectCoinCreatorFeeAllQuotesInstructions(user, feePayer, [delistedMint]);

Each quote's instructions are contiguous, so split the result per quote when it does not fit one transaction.

Fee Sharing

Fee sharing allows token creators to set up fee distribution to multiple shareholders. The OnlinePumpSdk provides methods to check distributable fees and distribute them.

Important: Reward split can be setup once and once only by calling either updateFeeShares or updateSharingConfigWithSocialRecipients. Double-check final recipients and shareBps before submitting.

Quote mints: updateFeeShares and distributeCreatorFees (v1), and the v1 transfer_creator_fees_to_pump consolidation the online helpers build, only handle SOL-quoted coins. A coin quoted in a token must use updateFeeSharesV2, distributeCreatorFeesV2 and transferCreatorFeesToPumpV2, passing the coin's quoteMint and the program that owns it as quoteTokenProgram (see Quote mints); the online helpers below take the same as options.

import { OnlinePumpSdk } from "@pump-fun/pump-sdk";

const connection = new Connection(
    "https://api.devnet.solana.com",
    "confirmed",
);
const onlineSdk = new OnlinePumpSdk(connection);
const mint = new PublicKey("...");

Check if Creator Has Migrated to Fee Sharing

Before checking or distributing fees, verify that the coin creator has set up fee sharing:

const usingSharingConfig = isCreatorUsingSharingConfig({ mint, creator });

if (!usingSharingConfig) {
    console.log("Creator has not set up fee sharing");
    return;
}

// Creator has migrated, proceed with fee distribution

Get Minimum Distributable Fee

Check whether a coin's fee sharing configuration balance and distributable fees

const result = await onlineSdk.getMinimumDistributableFee(mint);

console.log("Minimum required:", result.minimumRequired.toString());
console.log("Distributable fees:", result.distributableFees.toString());
console.log("Can distribute:", result.canDistribute);
console.log("Is graduated:", result.isGraduated);

This method handles both graduated (AMM) and non-graduated (bonding curve) tokens. For graduated tokens, it automatically consolidates fees from the AMM vault before calculating.

For a coin quoted in a token, pass the quote so the canonical pool (and therefore isGraduated) and the consolidation instruction are right:

const result = await onlineSdk.getMinimumDistributableFee(mint, simulationSigner, {
  quoteMint: bondingCurve.quoteMint,      // normalized: the zero key means SOL
  quoteTokenProgram,                      // optional; fetched from the mint when omitted
  payer,                                  // optional; signer for the V2 consolidation, defaults to simulationSigner
});

Note that the on-chain get_minimum_distributable_fee view reads the lamport creator vault only, so for a token quote minimumRequired, distributableFees and canDistribute describe SOL fees, not the quote-token fees; result.feesQuoteMint (always NATIVE_MINT today) says which mint the figures are in, so compare it with the coin's quote mint before gating on canDistribute. getCreatorVaultQuoteBalances reports token-quote amounts.

Distribute Creator Fees

Build instructions to distribute accumulated creator fees to shareholders:

// `payer` signs the creator-fee sweeps, needed once v3 / pool v2 trades left creator fees behind.
const { instructions, isGraduated, sweepCount } = await onlineSdk.buildDistributeCreatorFeesInstructions(mint, {
  payer,
});

// instructions contains:
// - sweep_creator_fee (curve and/or pool) first, when v3 / pool v2 trades left creator fees there
//   (`sweepCount` of them; send them in a transaction of their own if the whole list is too large)
// - For graduated tokens: transferCreatorFeesToPump + distributeCreatorFees
// - For non-graduated tokens: distributeCreatorFees only

// Add instructions to your transaction
const tx = new Transaction().add(...instructions);

This method automatically handles graduated tokens by including the transferCreatorFeesToPump instruction to consolidate fees from the AMM vault before distributing.

For a coin quoted in a token pass the quote and a payer (the V2 instructions may create token accounts); the quote token program is fetched from the mint when omitted:

const { instructions } = await onlineSdk.buildDistributeCreatorFeesInstructions(mint, {
  quoteMint: bondingCurve.quoteMint,
  payer,
});

GitHub Recipient and Social Fee PDA Requirements

If you are adding a GitHub recipient as a fee recipient in sharing config, make sure to initialize the social fee pda before adding it as a recipient. Use one of these methods:

import { Platform, PUMP_SDK } from "@pump-fun/pump-sdk";

// 1) Update an existing sharing config
await PUMP_SDK.updateSharingConfigWithSocialRecipients({
  authority,
  mint,
  currentShareholders,
  newShareholders: [
    { address: authority, shareBps: 7000 },
    { userId: "1234567", platform: Platform.GitHub, shareBps: 3000 },
  ],
});

// 2) Create sharing config + set social recipients in one flow
//    - Use pool for graduated coins or null for ungraduated
await PUMP_SDK.createSharingConfigWithSocialRecipients({
  creator,
  mint,
  pool,
  newShareholders: [
    { address: creator, shareBps: 7000 },
    { userId: "1234567", platform: Platform.GitHub, shareBps: 3000 },
  ],
});

Method selection:

  • updateSharingConfigWithSocialRecipients: use when sharing config already exists.
  • createSharingConfigWithSocialRecipients: use for first-time setup (creates config, then updates shares).

Important:

  • Social fee PDA creation is a one-time initialization per (userId, platform) and can be reused across coins once created.
  • Reward split can be setup once and once only by calling either updateFeeShares or updateSharingConfigWithSocialRecipients. Double-check final recipients and shareBps before submitting.

✅ Checklist

  • [ ] The GitHub user must be able to log in to claim fees. GitHub organizations are not supported for social fee recipients; adding an organization account can result in fees being permanently lost.
  • [ ] Only Platform.GitHub is supported. Any attempt to use a different platform value can result in the coin being banned or fees lost.
  • [ ] Fees in a GitHub vault can only be claimed by the linked GitHub user, and only through Pump.fun (web or mobile). You are responsible for directing users to claim there; we do not support any claim flow outside our apps.
  • [ ] You have initialized the social fee recipient pda by using one of the above helper or createSocialFeePda