# Pump SDK

Official Pump program SDK

# Updates

## 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](#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](#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`.

```Typescript
import { isSharingConfigEditable } from "@pump-fun/pump-sdk";
```

# Usage

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

## Coin creation

```Typescript
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

```Typescript
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

```Typescript
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,
});
```

## 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:

```Typescript
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 }]

// One mint, with what the builders need for it. Throws
// UnsupportedQuoteMintError when create_v2 would reject the mint.
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.

```Typescript
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)

```Typescript
// 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](#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:

```Typescript
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](#holder-reward-coins): 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.

```Typescript
// 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

```Typescript
// 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.

```Typescript
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`:

```Typescript
// 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

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

## Creator fees

```Typescript
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:

```Typescript
// 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](#quote-mints)); the online helpers below take the same as `options`.

```Typescript
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:

```Typescript
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

```Typescript
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:

```Typescript
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:

```Typescript
const { instructions, isGraduated } = await onlineSdk.buildDistributeCreatorFeesInstructions(mint);

// instructions contains:
// - 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:

```Typescript
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:

```ts
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`
