debpf
pump.fun / instructions

Instruction

sell_v3

Partly provenHidden

Undocumented (not in the IDL) sell for pump.fun bonding curves that works with either SOL or an SPL quote token (e.g. the PUMP-quoted curves). Anyone holding the token can call it. The seller sends `amount` base tokens to the curve and gets back the constant-product quote minus a 0.95% protocol fee and a creator fee (0.30% by default; a per-curve override can raise it, e.g. 1% was seen). Both fees are rounded up. Only half the protocol fee is paid out to the fee recipient right away (global split = 5000 bps); the other half and the whole creator fee stay inside the bonding curve account and are only recorded in its fields, to be swept out later. Fails on amount 0, insufficient balance, or net output below min_quote_out (TooLittleSolReceived 6003).

Discriminator
0x1c92de7726c469d5
Calls in the sample
27
Reproduced, seen by the agent
2 / 16
Reproduced, never shown to the agent
2 / 10

4 of 26 real mainnet calls reproduced exactly. Every SOL and token movement the model predicted matched the chain to the last unit. Unseen calls were never shown to the agent.

Bytecodefn_245e9
245e9mov64 r7, r5
245eamov64 r9, r4
245ebmov64 r8, r3
245ecmov64 r6, r2
245edstxdw [r10-432], r1
245eelddw r1, 0x1ae41d ; "Instruction: SellV3"
245f0mov64 r2, 0x13
245f1call sol_log_
245f2ldxdw r1, [r7-4088]
245f3jlt r1, 0x8, +83 ; -> 24647
245f4and64 r1, -0x8
245f5jeq r1, 0x8, +81 ; -> 24647
245f6ldxdw r1, [r7-4096]
245f7ldxdw r2, [r1+0]
245f8stxdw [r10-440], r2
245f9ldxdw r1, [r1+8]
245fastxdw [r10-448], r1
245fbmov64 r1, -0x1
245fcstxb [r10-372], r1
245fdstxw [r10-376], r1
245festxdw [r10-360], r9
245ffstxdw [r10-368], r8
24600mov64 r1, r10
24601add64 r1, -0x178
24602stxdw [r10-4088], r1
24603mov64 r1, r10
24604add64 r1, -0xb0
24605mov64 r3, r10
24606add64 r3, -0x170
24607mov64 r5, r10
24608mov64 r2, r6
24609call fn_1f826
2460aldxdw r8, [r10-168]
2460bldxdw r7, [r10-176]
2460cldxb r9, [r10-6]
2460djeq r9, 0x2, +76 ; -> 2465a
2460emov64 r1, r10
2460fadd64 r1, -0x150
24610mov64 r2, r10
24611add64 r2, -0xa0
24612mov64 r3, 0x9a
24613call fn_35367
24614ldxw r1, [r10-5]
24615stxw [r10-181], r1
24616ldxb r1, [r10-1]
24617stxb [r10-177], r1
24618stxb [r10-182], r9
24619stxdw [r10-344], r8
2461astxdw [r10-352], r7
2461bldxw r1, [r10-376]
2461cstxw [r10-144], r1
2461dldxb r1, [r10-372]
2461estxb [r10-140], r1
2461fldxdw r1, [r10-360]
24620stxdw [r10-152], r1
24621ldxdw r1, [r10-368]
24622stxdw [r10-160], r1
24623mov64 r1, r10
24624add64 r1, -0x160
24625stxdw [r10-168], r1
24626stxdw [r10-176], r6
24627mov64 r1, r10
24628add64 r1, -0x188
24629mov64 r2, r10
2462aadd64 r2, -0xb0
2462bldxdw r3, [r10-440]
2462cldxdw r4, [r10-448]
2462dcall fn_28613
2462eldxdw r7, [r10-392]
2462fjeq r7, 0x2, +1 ; -> 24631
24630ja +45 ; -> 2465e
24631mov64 r1, r10
24632add64 r1, -0x198
24633mov64 r2, r10
24634add64 r2, -0x160
24635mov64 r3, r6
24636call fn_202de
24637ldxdw r1, [r10-208]
24638ldxdw r2, [r10-216]
24639ldxdw r3, [r2+0]
2463aadd64 r3, -0x1
2463bldxdw r8, [r10-400]
2463cldxdw r7, [r10-408]
2463dstxdw [r2+0], r3
2463ejne r3, 0x0, +3 ; -> 24642
2463fldxdw r3, [r2+8]
24640add64 r3, -0x1
24641stxdw [r2+8], r3
24642ldxdw r2, [r1+0]
24643add64 r2, -0x1
24644stxdw [r1+0], r2
24645jne r2, 0x0, +20 ; -> 2465a
24646ja +37 ; -> 2466c
24647lddw r1, 0x1b3c60
24649call fn_33e71
2464amov64 r1, r0
2464band64 r1, 0x3
2464cmov64 r2, r1
2464dadd64 r2, -0x2
2464ejlt r2, 0x2, +5 ; -> 24654
2464fjeq r1, 0x0, +4 ; -> 24654
24650ldxdw r1, [r0-1]
24651ldxdw r2, [r0+7]
24652ldxdw r2, [r2+0]
24653callx r2
24654mov64 r1, r10
24655add64 r1, -0x1a8
24656mov64 r2, 0x66
24657call fn_32b09
24658ldxdw r8, [r10-416]
24659ldxdw r7, [r10-424]
2465aldxdw r1, [r10-432]
2465bstxdw [r1+8], r8
2465cstxdw [r1+0], r7
2465dexit
2465eldxdw r8, [r10-384]
2465fldxdw r1, [r10-208]
24660ldxdw r2, [r10-216]
24661ldxdw r3, [r2+0]
24662add64 r3, -0x1
24663stxdw [r2+0], r3
24664jne r3, 0x0, +3 ; -> 24668
24665ldxdw r3, [r2+8]
24666add64 r3, -0x1
24667stxdw [r2+8], r3
24668ldxdw r2, [r1+0]
24669add64 r2, -0x1
2466astxdw [r1+0], r2
2466bjne r2, 0x0, -18 ; -> 2465a
2466cldxdw r2, [r1+8]
2466dadd64 r2, -0x1
2466estxdw [r1+8], r2
2466fja -22 ; -> 2465a
Reconstructedsell_v3
// discriminator 1c92de7726c469d5 (hidden: not in published IDL)
// accounts: 0 global, 1 base_mint, 2 quote_mint, 3 base_token_program, 4 quote_token_program,
// 5 bonding_curve (mut), 6 associated_base_bonding_curve (mut), 7 associated_quote_bonding_curve (mut; unused/empty for SOL),
// 8 user (signer, mut), 9 associated_base_user (mut), 10 associated_quote_user (mut),
// 11 user_volume_accumulator (mut), 12 fee_config (pfee program), 13 fee_recipient (SOL wallet, or its quote ATA),
// 14 system_program, 15 event_authority, 16 program
fn sell_v3(ctx, amount: u64, min_quote_out: u64) -> Result<()> { // fn_245e9
msg!("Instruction: SellV3");
require!(ix_data.len() >= 16); // two u64 args
TradeV3Accounts::try_accounts(ctx)?; // fn_1f826: PDA/owner/mint/ATA checks, shared with buy_v3 / buy_exact_quote_in_v3
let bc = &mut ctx.bonding_curve;
check_curve_state(bc)?; // fn_076ea / fn_0f4b6 (complete / mode flags)
require!(amount != 0, Err(6022)); // pc 2862e
require!(user_base_ata.amount >= amount, Err(6023)); // pc 28631
// constant product quote, floored fn_1341e
let gross = (bc.virtual_quote as u128 * amount as u128 / (bc.virtual_token + amount) as u128) as u64;
// fees fn_0f803 -> fn_109ae (util/fee.rs)
// bps from fee_config tiers by market cap (currently flat: protocol 95, creator 30, lp 0);
// hardcoded creator addresses get special fee sets; if global flag set and curve.creator_fee_bps_override != 0 it is used
let protocol_fee = ceil_div(gross * protocol_bps, 10_000); // fn_107c7
let creator_fee = ceil_div(gross * creator_bps, 10_000);
let net = gross.checked_sub(protocol_fee).and_then(|x| x.checked_sub(creator_fee)).ok_or(6024)?; // fn_0f8d7
require!(net >= min_quote_out, Err(TooLittleSolReceived /*6003*/)); // pc 286f5
// reserves: virtual_token += amount; real_token += amount; virtual_quote -= gross; real_quote -= gross (fn_135f3, checked)
// base tokens user -> curve fn_11594: transfer_checked(base_token_program, user_base_ata -> curve_base_ata, amount, user signs)
// quote out to user fn_12120
if quote_mint == native { move_lamports(bonding_curve -> user, net); }
else { transfer_checked(quote_token_program, curve_quote_ata -> user_quote_ata, net, signer = ["bonding-curve", base_mint, bump]); }
// protocol-fee split fn_136f2
let to_recipient = if bc.flag_154 { 0 } else { protocol_fee * global.fee_split_bps /*5000*/ / 10_000 }; // floor; split_bps <= 9999 enforced
bc.retained_protocol += protocol_fee - to_recipient; // curve field +120, stays in curve account
bc.accrued_creator += creator_fee; // curve field +112, stays in curve account
pay_from_curve(fee_recipient, to_recipient); // fn_12196: lamports (SOL) or PDA-signed transfer_checked (token)
update_user_volume_accumulator(...); // fn_0222b
emit_cpi!(TradeEvent { mint, sol_amount, token_amount: amount, is_buy: false, user, timestamp,
virtual/real reserves, fee_recipient, fee_bps, fee: protocol_fee, creator, creator_fee_bps, creator_fee,
ix_name: "sell", buyback_bps: 5000, buyback_fee: to_recipient, quote_mint, quote_amount: gross,
virtual_quote, real_quote, ... }); // via "__event_authority"
Ok(())
}

Replay model

The executable model the agent wrote. Every tally above comes from running it against mainnet.

function rd(d,o){let x=0n;for(let i=7;i>=0;i--)x=(x<<8n)|BigInt(d[o+i]);return x;}
function model(ctx){
const d=ctx.data; const amount=rd(d,8);
const A=ctx.accounts;
const INIT_VTOK=1073000000000000n, INIT_VSOL=30000000000n, SUPPLY=1000000000000000n;
const curveAta=A[6].token.amount;
const vtok=curveAta + INIT_VTOK - SUPPLY;
const k=INIT_VSOL*INIT_VTOK;
let vsol=(k + vtok - 1n)/vtok; // ceil
const gross=vsol*amount/(vtok+amount);
const ceil=(a,b)=>(a+b-1n)/b;
const protocol=ceil(gross*95n,10000n), creator=ceil(gross*30n,10000n);
const toRecipient=protocol*5000n/10000n;
const net=gross-protocol-creator;
const quoteIsToken = A[7].token!=null;
const out={lamports:{},tokens:{}};
out.tokens[6]=amount; out.tokens[9]=-amount;
if(!quoteIsToken){ out.lamports[5]=-(net+toRecipient); out.lamports[13]=toRecipient; }
else { out.tokens[7]=-(net+toRecipient); out.tokens[13]=toRecipient; out.tokens[10]=net; }
return out;
}

Accounts

Not published. The accounts and arguments were recovered from the bytecode; see the reconstruction.

program 6EF8rr…BEwF6P