$npx -y skills add agiprolabs/claude-trading-skills --skill pumpfun-mechanicsPumpFun bonding curve math, graduation mechanics, instruction parsing, and PumpSwap migration
| 1 | # PumpFun Mechanics — Bonding Curves, Graduation & Instruction Parsing |
| 2 | |
| 3 | PumpFun is the dominant Solana token launchpad. Understanding its bonding curve math, graduation process, and instruction formats is essential for analyzing new token launches, building trading strategies around graduation events, and parsing on-chain PumpFun activity. |
| 4 | |
| 5 | ## Bonding Curve Math |
| 6 | |
| 7 | PumpFun uses a **virtual constant-product (CPMM)** bonding curve: |
| 8 | |
| 9 | ``` |
| 10 | k = virtualSolReserves × virtualTokenReserves |
| 11 | ``` |
| 12 | |
| 13 | ### Initial Parameters |
| 14 | |
| 15 | | Parameter | Value | |
| 16 | |-----------|-------| |
| 17 | | Initial Virtual SOL | 30 SOL (30,000,000,000 lamports) | |
| 18 | | Initial Virtual Tokens | ~1.073B tokens (1,073,000,000,000,000 raw, 6 decimals) | |
| 19 | | Token Total Supply | 1B tokens (1,000,000,000,000,000 raw) | |
| 20 | | Real Token Reserves | ~793M tokens (793,000,000,000,000 raw) | |
| 21 | | Real SOL Reserves | 0 (no real SOL at launch) | |
| 22 | | Fee | 1% (applied externally by the program) | |
| 23 | |
| 24 | **Virtual vs Real**: Virtual reserves define the curve shape. Real reserves track actual withdrawable funds. The difference (1.073B - 793M = 280M virtual tokens) shapes the initial price but can never be withdrawn. |
| 25 | |
| 26 | ### Spot Price |
| 27 | |
| 28 | ```python |
| 29 | price_sol_per_token = virtual_sol_reserves / virtual_token_reserves |
| 30 | |
| 31 | # In human-readable units: |
| 32 | price = (virtual_sol / 1e9) / (virtual_token / 1e6) |
| 33 | |
| 34 | # At genesis: 30 / 1,073,000,000 ≈ 2.796e-8 SOL/token |
| 35 | # At graduation: ~4.1e-7 SOL/token (~14.7x from launch) |
| 36 | ``` |
| 37 | |
| 38 | ### Buy Tokens (SOL → Tokens) |
| 39 | |
| 40 | ```python |
| 41 | def buy_tokens(v_sol: int, v_tok: int, real_tok: int, sol_in: int) -> int: |
| 42 | """Calculate tokens received for a given SOL input. |
| 43 | |
| 44 | Args: |
| 45 | v_sol: Virtual SOL reserves (lamports). |
| 46 | v_tok: Virtual token reserves (raw). |
| 47 | real_tok: Real token reserves (raw). |
| 48 | sol_in: SOL to spend (lamports, BEFORE 1% fee). |
| 49 | |
| 50 | Returns: |
| 51 | Tokens received (raw units). |
| 52 | """ |
| 53 | k = v_sol * v_tok |
| 54 | new_v_sol = v_sol + sol_in |
| 55 | new_v_tok = k // new_v_sol + 1 # +1 matches on-chain rounding |
| 56 | tokens_out = v_tok - new_v_tok |
| 57 | return min(tokens_out, real_tok) |
| 58 | ``` |
| 59 | |
| 60 | ### Sell Tokens (Tokens → SOL) |
| 61 | |
| 62 | ```python |
| 63 | def sell_tokens(v_sol: int, v_tok: int, real_sol: int, tokens_in: int) -> int: |
| 64 | """Calculate SOL received for selling tokens. |
| 65 | |
| 66 | Args: |
| 67 | v_sol: Virtual SOL reserves (lamports). |
| 68 | v_tok: Virtual token reserves (raw). |
| 69 | real_sol: Real SOL reserves (lamports). |
| 70 | tokens_in: Tokens to sell (raw units). |
| 71 | |
| 72 | Returns: |
| 73 | SOL received (lamports, BEFORE 1% fee). |
| 74 | """ |
| 75 | k = v_sol * v_tok |
| 76 | new_v_tok = v_tok + tokens_in |
| 77 | new_v_sol = k // new_v_tok |
| 78 | sol_out = v_sol - new_v_sol - 1 # -1 matches on-chain floor rounding |
| 79 | return min(sol_out, real_sol) |
| 80 | ``` |
| 81 | |
| 82 | ### Buy Cost (Exact token amount → SOL needed) |
| 83 | |
| 84 | ```python |
| 85 | def buy_cost(v_sol: int, v_tok: int, tokens_wanted: int) -> int: |
| 86 | """Calculate SOL needed to buy exact token amount. |
| 87 | |
| 88 | Returns: |
| 89 | SOL cost in lamports (before fee). Returns max int if impossible. |
| 90 | """ |
| 91 | if tokens_wanted >= v_tok: |
| 92 | return 2**64 - 1 # impossible |
| 93 | k = v_sol * v_tok |
| 94 | new_v_tok = v_tok - tokens_wanted |
| 95 | new_v_sol = k // new_v_tok + 1 |
| 96 | return new_v_sol - v_sol |
| 97 | ``` |
| 98 | |
| 99 | ### Fee Handling |
| 100 | |
| 101 | The 1% fee is **not** part of the curve math. It's applied externally: |
| 102 | |
| 103 | ```python |
| 104 | # Buying: fee deducted from SOL input before curve |
| 105 | actual_sol_to_curve = sol_input * 0.99 |
| 106 | |
| 107 | # Selling: fee deducted from SOL output after curve |
| 108 | actual_sol_received = sol_from_curve * 0.99 |
| 109 | |
| 110 | # Roundtrip minimum cost: ~2% from fees alone, plus price impact |
| 111 | ``` |
| 112 | |
| 113 | ### Market Cap |
| 114 | |
| 115 | ```python |
| 116 | market_cap_sol = (token_total_supply * virtual_sol_reserves) / virtual_token_reserves |
| 117 | ``` |
| 118 | |
| 119 | ## Graduation |
| 120 | |
| 121 | Graduation occurs when `realSolReserves` reaches **~85 SOL** (~$12K-14K depending on SOL price). Only ~1.4% of PumpFun tokens ever graduate. |
| 122 | |
| 123 | ### What Happens |
| 124 | |
| 125 | 1. `complete` flag set to `true` on bonding curve account |
| 126 | 2. `CompleteEvent` emitted (discriminator `5f72619cd42e9808`) |
| 127 | 3. Bonding curve stops accepting trades |
| 128 | 4. ~$12K liquidity deposited to the destination DEX |
| 129 | 5. Token becomes tradeable on PumpSwap (or Raydium for older tokens) |
| 130 | |
| 131 | ### Fill Percentage |
| 132 | |
| 133 | ```python |
| 134 | GRADUATION_THRESHOLD = 85_000_000_000 # 85 SOL in lamports |
| 135 | |
| 136 | fill_pct = (real_sol_reserves / GRADUATION_THRESHOLD) * 100.0 |
| 137 | ``` |
| 138 | |
| 139 | ### Migration Targets |
| 140 | |
| 141 | - **March 2025+**: PumpSwap (`pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA`) — native AMM, no migration fee |
| 142 | - **Before March 2025**: Raydium V4 (`675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`) — 6 SOL fee |
| 143 | |
| 144 | ### PumpSwap Post-Graduation |
| 145 | |
| 146 | PumpSwap is a constant-product AMM with 1% fee (same as bonding curve). Key differences: |
| 147 | - Base asset is always WSOL, quote is token |
| 148 | - Instruction semantics are inverted: "buy" instruction sells tokens, "sell" instruction buys tokens |
| 149 | - Supports creator revenue sharing (0.05% of volume to original creator) |
| 150 | |
| 151 | ## Program IDs & Address |