debpf
pump.fun / instructions

Instruction

buy_exact_quote_in_v3

DecompiledHidden

Hidden instruction (not in the public IDL). Spends an exact amount of quote currency (SOL or a token such as PUMP) on a bonding curve and gives the buyer the resulting base tokens. Anyone can call it. Fees come out of the amount spent: 95 bps protocol plus the curve's creator bps (30 by default; some curves set their own, e.g. 100), each rounded up. Half of the protocol fee (global buyback_bps = 5000) goes straight to the fee recipient. The other half and the creator fee stay inside the bonding curve until the hidden sweep instructions move them. If the curve doesn't have enough tokens left, the buyer gets the remainder and pays only what that costs. Errors: zero min_tokens_out (6020), zero spend or spend too small to cover fees (6041), fewer tokens than min_tokens_out (slippage, 6042), partial fill not allowed (6021), or the partial-fill cost exceeding the spend (6002).

Discriminator
0xe1f7501ed5b38488
Calls in the sample
67
Reproduced, seen by the agent
0 / 39
Reproduced, never shown to the agent
0 / 28

0 of 67 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_2453d
2453dmov64 r6, r5
2453emov64 r8, r4
2453fmov64 r9, r3
24540mov64 r7, r2
24541stxdw [r10-432], r1
24542lddw r1, 0x1ae3ff ; "Instruction: BuyExactQuoteInV3"
24544mov64 r2, 0x1e
24545call sol_log_
24546ldxdw r1, [r6-4088]
24547jlt r1, 0x8, +96 ; -> 245a8
24548mov64 r2, r1
24549and64 r2, -0x8
2454ajeq r2, 0x8, +93 ; -> 245a8
2454bldxdw r2, [r6-4096]
2454cldxdw r3, [r2+0]
2454dmov64 r5, 0x0
2454eldxdw r4, [r2+8]
2454fjeq r1, 0x10, +4 ; -> 24554
24550ldxb r1, [r2+16]
24551jeq r1, 0x0, +2 ; -> 24554
24552jne r1, 0x1, +124 ; -> 245cf
24553mov64 r5, 0x1
24554stxdw [r10-456], r5
24555stxdw [r10-448], r4
24556stxdw [r10-440], r3
24557mov64 r1, -0x1
24558stxb [r10-372], r1
24559stxw [r10-376], r1
2455astxdw [r10-8], r8
2455bstxdw [r10-16], r9
2455cmov64 r1, r10
2455dadd64 r1, -0x178
2455estxdw [r10-4088], r1
2455fmov64 r1, r10
24560add64 r1, -0xc0
24561mov64 r3, r10
24562add64 r3, -0x10
24563mov64 r5, r10
24564mov64 r2, r7
24565call fn_1f826
24566ldxdw r8, [r10-184]
24567ldxdw r6, [r10-192]
24568ldxb r9, [r10-22]
24569jeq r9, 0x2, +81 ; -> 245bb
2456amov64 r1, r10
2456badd64 r1, -0x160
2456cmov64 r2, r10
2456dadd64 r2, -0xb0
2456emov64 r3, 0x9a
2456fcall fn_35367
24570ldxw r1, [r10-21]
24571stxw [r10-197], r1
24572ldxb r1, [r10-17]
24573stxb [r10-193], r1
24574stxb [r10-198], r9
24575stxdw [r10-360], r8
24576stxdw [r10-368], r6
24577ldxw r1, [r10-376]
24578stxw [r10-160], r1
24579ldxb r1, [r10-372]
2457astxb [r10-156], r1
2457bldxdw r1, [r10-8]
2457cstxdw [r10-168], r1
2457dldxdw r1, [r10-16]
2457estxdw [r10-176], r1
2457fmov64 r1, r10
24580add64 r1, -0x170
24581stxdw [r10-184], r1
24582stxdw [r10-192], r7
24583mov64 r1, r10
24584add64 r1, -0x188
24585mov64 r2, r10
24586add64 r2, -0xc0
24587ldxdw r3, [r10-440]
24588ldxdw r4, [r10-448]
24589ldxdw r5, [r10-456]
2458acall fn_2835c
2458bldxdw r6, [r10-392]
2458cjeq r6, 0x2, +1 ; -> 2458e
2458dja +49 ; -> 245bf
2458emov64 r1, r10
2458fadd64 r1, -0x198
24590mov64 r2, r10
24591add64 r2, -0x170
24592mov64 r3, r7
24593call fn_202de
24594ldxdw r1, [r10-224]
24595ldxdw r2, [r10-232]
24596ldxdw r3, [r2+0]
24597add64 r3, -0x1
24598ldxdw r8, [r10-400]
24599ldxdw r6, [r10-408]
2459astxdw [r2+0], r3
2459bjne r3, 0x0, +3 ; -> 2459f
2459cldxdw r3, [r2+8]
2459dadd64 r3, -0x1
2459estxdw [r2+8], r3
2459fldxdw r2, [r1+0]
245a0add64 r2, -0x1
245a1stxdw [r1+0], r2
245a2ldxdw r4, [r10-432]
245a3jne r2, 0x0, +24 ; -> 245bc
245a4ldxdw r2, [r1+8]
245a5add64 r2, -0x1
245a6stxdw [r1+8], r2
245a7ja +20 ; -> 245bc
245a8lddw r1, 0x1b3c60
245aacall fn_33e71
245abmov64 r1, r0
245acand64 r1, 0x3
245admov64 r2, r1
245aeadd64 r2, -0x2
245afjlt r2, 0x2, +5 ; -> 245b5
245b0jeq r1, 0x0, +4 ; -> 245b5
245b1ldxdw r1, [r0-1]
245b2ldxdw r2, [r0+7]
245b3ldxdw r2, [r2+0]
245b4callx r2
245b5mov64 r1, r10
245b6add64 r1, -0x1a8
245b7mov64 r2, 0x66
245b8call fn_32b09
245b9ldxdw r8, [r10-416]
245baldxdw r6, [r10-424]
245bbldxdw r4, [r10-432]
245bcstxdw [r4+8], r8
245bdstxdw [r4+0], r6
245beexit
245bfldxdw r8, [r10-384]
245c0ldxdw r1, [r10-224]
245c1ldxdw r2, [r10-232]
245c2ldxdw r3, [r2+0]
245c3add64 r3, -0x1
245c4stxdw [r2+0], r3
245c5ldxdw r4, [r10-432]
245c6jne r3, 0x0, +3 ; -> 245ca
245c7ldxdw r3, [r2+8]
245c8add64 r3, -0x1
245c9stxdw [r2+8], r3
245caldxdw r2, [r1+0]
245cbadd64 r2, -0x1
245ccstxdw [r1+0], r2
245cdjne r2, 0x0, -18 ; -> 245bc
245ceja -43 ; -> 245a4
245cfstxb [r10-376], r1
245d0lddw r1, 0x1b3d30
245d2stxdw [r10-192], r1
245d3mov64 r1, r10
245d4add64 r1, -0x10
245d5stxdw [r10-176], r1
245d6lddw r1, 0x1a96e0
245d8stxdw [r10-8], r1
245d9mov64 r1, r10
245daadd64 r1, -0x178
245dbstxdw [r10-16], r1
245dcstdw [r10-160], 0x0
245ddstdw [r10-184], 0x1
245destdw [r10-168], 0x1
245dfmov64 r6, r10
245e0add64 r6, -0x170
245e1mov64 r2, r10
245e2add64 r2, -0xc0
245e3mov64 r1, r6
245e4call fn_342ee
245e5mov64 r1, 0x15
245e6mov64 r2, r6
245e7call fn_01495
245e8ja -62 ; -> 245ab
Reconstructedbuy_exact_quote_in_v3
// discriminator e1f7501ed5b38488 ; handler fn_2453d -> logic fn_2835c (programs/pump/src/trade_v3.rs)
// accounts (17): 0 global, 1 base_mint, 2 quote_mint, 3 base_token_program, 4 quote_token_program,
// 5 bonding_curve (mut), 6 curve_base_ata (mut), 7 curve_quote_ata (mut, unused for SOL), 8 user (signer),
// 9 user_base_ata (mut), 10 user_quote_ata (mut), 11 user_volume_accumulator (mut), 12 fee_config (pump fees program),
// 13 buyback_fee_recipient (SOL wallet or its quote ATA, mut), 14 system_program, 15 event_authority, 16 program
pub fn buy_exact_quote_in_v3(ctx, spendable_quote_in: u64, min_tokens_out: u64, flag: Option<bool> /* byte 16: 0/1, other -> error */) {
msg!("Instruction: BuyExactQuoteInV3");
trade_v3_accounts_validate(ctx)?; // fn_1f826: PDAs, owners, mints, user_volume_accumulator init
let curve = &mut ctx.bonding_curve;
require!(!curve.complete ...); // fn_076ea / fn_0f4b6 state checks
require!(min_tokens_out != 0, 6020); // pc 28377
require!(spendable_quote_in != 0, 6041); // pc 28379
let fee_exempt = ctx.user.key == global.fee_exempt_key; // global +0x288, pc 283a2
let (net, protocol_fee, creator_fee, p_bps, c_bps);
if fee_exempt {
net = spendable_quote_in; protocol_fee = 0; creator_fee = 0; // pc 2845a
} else {
// fn_0f803 / fn_109ae: bps from FeeConfig. Market-cap tier for SOL/known quote mints
// (mcap = v_quote*supply/v_token), flat fees otherwise. Current config: 95 / 30 in every tier.
// If global enables it and curve.creator_fee_bps != 0 -> c_bps = curve.creator_fee_bps.
(p_bps, c_bps) = select_fee_bps(fee_config, curve, quote_mint);
if curve.creator == Pubkey::default() { c_bps = 0; }
// fn_0f91f
net = spendable_quote_in * 10_000 / (10_000 + p_bps + c_bps); // floor
protocol_fee = ceil(net * p_bps / 10_000);
creator_fee = ceil(net * c_bps / 10_000);
if net + protocol_fee + creator_fee > spendable_quote_in {
net -= net + protocol_fee + creator_fee - spendable_quote_in; // fees are not recomputed
}
require!(net != 0, 6041);
}
// fn_1347e / fn_105eb (note the -1)
let mut tokens = (net - 1) * curve.virtual_token_reserves / (curve.virtual_quote_reserves + net - 1);
require!(tokens != 0); // pc 283cb
if tokens > curve.real_token_reserves { // pc 2847d
// partial fill allowed unless (curve flag +162 set or user is fee-exempt) and flag == false -> 6021
tokens = curve.real_token_reserves;
let q = curve.virtual_quote_reserves * tokens / (curve.virtual_token_reserves - tokens) + 1; // fn_13385
(protocol_fee, creator_fee) = compute_trade_fees(q); // fn_0f803, ceil each
let cost = q + protocol_fee + creator_fee;
require!(cost <= spendable_quote_in, 6002); // pc 2855b
net = q;
} else {
require!(tokens >= min_tokens_out, 6042); // pc 284bc slippage
}
// settle: fn_0fd9b
curve.virtual_token_reserves -= tokens; curve.real_token_reserves -= tokens; // fn_134f5
curve.virtual_quote_reserves += net; curve.real_quote_reserves += net;
token::transfer_checked(curve_base_ata -> user_base_ata, tokens, signer = ["bonding-curve", base_mint]); // fn_1148a
if user_volume_accumulator.user == default { user_volume_accumulator.user = user; }
// fn_136f2
let buyback = if curve.flag154 { 0 } else { protocol_fee * global.buyback_bps / 10_000 }; // 5000 bps now
curve.accrued_protocol_fee += protocol_fee - buyback; // curve +120, stays in the curve
curve.accrued_creator_fee += creator_fee; // curve +112, stays in the curve
let total = net + protocol_fee + creator_fee;
// fn_1229d / fn_11ad5 / fn_1202e
if quote_mint == WSOL {
system_transfer(user -> bonding_curve, total - buyback);
system_transfer(user -> buyback_fee_recipient, buyback);
} else {
token::transfer_checked(user_quote_ata -> curve_quote_ata, total - buyback);
token::transfer_checked(user_quote_ata -> buyback_fee_recipient_quote_ata, buyback);
}
emit!(TradeEvent { mint, quote_amount: .., token_amount: tokens, is_buy: true, user, reserves.., fee_recipient,
fee_bps: p_bps, fee: protocol_fee, creator, creator_fee_bps: c_bps, creator_fee,
ix_name: "buy_exact_quote_in", .. }); // fn_10150
}

Replay model

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

function rd(d,o){let v=0n;for(let i=7;i>=0;i--)v=(v<<8n)|BigInt(d[o+i]);return v;}
function cdiv(a,b){return (a+b-1n)/b;}
function model(ctx){
const d=ctx.data; const spend=rd(d,8);
const A=ctx.accounts;
const isSol = A[2].pubkey.startsWith('So11111111111111111111111111111111111111112');
const P=95n, C=30n, BUYBACK=5000n;
let net = spend*10000n/(10000n+P+C);
const pf = cdiv(net*P,10000n), cf = cdiv(net*C,10000n);
if (net+pf+cf>spend) net -= (net+pf+cf-spend);
const total = net+pf+cf;
const buyback = pf*BUYBACK/10000n;
// estimate reserves (SOL curves, default 1.073e15/30 SOL init)
const ata=A[6].token.amount;
const vt = ata + 73000000000000n;
const k = 30000000000n*1073000000000000n;
const vq = cdiv(k,vt);
const x=net-1n;
const tokens = x*vt/(vq+x);
const out={lamports:{},tokens:{}};
out.tokens[6]=-tokens; out.tokens[9]=tokens;
if(isSol){ out.lamports[5]=total-buyback; out.lamports[13]=buyback; }
else { out.tokens[7]=total-buyback; out.tokens[13]=buyback; }
return out;
}

Accounts

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

program 6EF8rr…BEwF6P