Instruction
buy_exact_quote_in_v2
Any wallet can call this to spend an exact amount of quote currency (SOL, or a token such as PUMP) on a pump.fun bonding curve and receive the base token. Fees come out of the amount spent: a protocol fee (95 bps now, read from the pump fee program by market cap) and a creator fee (30 bps by default; a curve can store its own value, e.g. 100 bps, when a Global flag allows it). Both fees are rounded up. Unlike v3, all fees are paid out right away: Global.buyback_bps (5000, so half) of the protocol fee goes to the buyback recipient, unless the curve is in mayhem mode, the rest goes to the fee recipient, and the creator fee goes to the creator vault (or to the buyer's cashback accumulator on cashback curves). One user address stored in Global pays no fees at all. Errors: min_tokens_out = 0 (6020), spend = 0 or too small (6041), curve complete (6005), output below min_tokens_out (6042), not enough tokens left unless the partial-fill flag is set (6021), partial-fill cost above spend (6002), wrong quote mint (6063).
- Discriminator
- 0xc2ab1c46684d5b2f
- Calls in the sample
- 66
- Reproduced, seen by the agent
- 3 / 47
- Reproduced, never shown to the agent
- 0 / 17
3 of 64 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.
24323mov64 r6, r524324mov64 r8, r424325mov64 r9, r324326mov64 r7, r224327stxdw [r10-952], r124328lddw r1, 0x1ae3bc ; "Instruction: BuyExactQuoteInV2"2432amov64 r2, 0x1e2432bcall sol_log_2432cldxdw r1, [r6-4088]2432djlt r1, 0x8, +109 ; -> 2439b2432emov64 r2, r12432fand64 r2, -0x824330jeq r2, 0x8, +106 ; -> 2439b24331ldxdw r2, [r6-4096]24332ldxdw r3, [r2+0]24333mov64 r5, 0x024334ldxdw r4, [r2+8]24335jeq r1, 0x10, +4 ; -> 2433a24336ldxb r1, [r2+16]24337jeq r1, 0x0, +2 ; -> 2433a24338jne r1, 0x1, +153 ; -> 243d224339mov64 r5, 0x12433astxdw [r10-976], r52433bstxdw [r10-968], r42433cstxdw [r10-960], r32433dstdw [r10-891], -0x12433estdw [r10-896], -0x12433fstxdw [r10-8], r824340stxdw [r10-16], r924341mov64 r1, r1024342add64 r1, -0x38024343stxdw [r10-4088], r124344mov64 r1, r1024345add64 r1, -0x1c024346mov64 r3, r1024347add64 r3, -0x1024348mov64 r5, r1024349mov64 r2, r72434acall fn_13be62434bldxdw r8, [r10-432]2434cldxdw r6, [r10-440]2434dldxdw r9, [r10-448]2434elddw r1, 0x800000000000000024350jeq r9, r1, +93 ; -> 243ae24351mov64 r1, r1024352add64 r1, -0x35824353mov64 r2, r1024354add64 r2, -0x1a824355mov64 r3, 0x19824356call fn_3536724357stxdw [r10-864], r824358stxdw [r10-872], r624359stxdw [r10-880], r92435aldxdw r1, [r10-896]2435bstxdw [r10-416], r12435cldxdw r1, [r10-891]2435dstxdw [r10-411], r12435eldxdw r1, [r10-8]2435fstxdw [r10-424], r124360ldxdw r1, [r10-16]24361stxdw [r10-432], r124362mov64 r1, r1024363add64 r1, -0x37024364stxdw [r10-440], r124365stxdw [r10-448], r724366mov64 r1, r1024367add64 r1, -0x39024368mov64 r2, r1024369add64 r2, -0x1c02436aldxdw r3, [r10-960]2436bldxdw r4, [r10-968]2436cldxdw r5, [r10-976]2436dcall fn_272152436eldxdw r6, [r10-912]2436fjeq r6, 0x2, +1 ; -> 2437124370ja +65 ; -> 243b224371mov64 r1, r1024372add64 r1, -0x3a024373mov64 r2, r1024374add64 r2, -0x37024375mov64 r3, r724376call fn_14b4624377ldxdw r1, [r10-720]24378ldxdw r2, [r10-728]24379ldxdw r3, [r2+0]2437aadd64 r3, -0x12437bldxdw r8, [r10-920]2437cldxdw r6, [r10-928]2437dstxdw [r2+0], r32437ejne r3, 0x0, +3 ; -> 243822437fldxdw r3, [r2+8]24380add64 r3, -0x124381stxdw [r2+8], r324382ldxdw r2, [r1+0]24383add64 r2, -0x124384stxdw [r1+0], r224385ldxdw r4, [r10-952]24386jne r2, 0x0, +3 ; -> 2438a24387ldxdw r2, [r1+8]24388add64 r2, -0x124389stxdw [r1+8], r22438aldxdw r1, [r10-672]2438bldxdw r2, [r10-680]2438cldxdw r3, [r2+0]2438dadd64 r3, -0x12438estxdw [r2+0], r32438fjne r3, 0x0, +3 ; -> 2439324390ldxdw r3, [r2+8]24391add64 r3, -0x124392stxdw [r2+8], r324393ldxdw r2, [r1+0]24394add64 r2, -0x124395stxdw [r1+0], r224396jne r2, 0x0, +24 ; -> 243af24397ldxdw r2, [r1+8]24398add64 r2, -0x124399stxdw [r1+8], r22439aja +20 ; -> 243af2439blddw r1, 0x1b3c602439dcall fn_33e712439emov64 r1, r02439fand64 r1, 0x3243a0mov64 r2, r1243a1add64 r2, -0x2243a2jlt r2, 0x2, +5 ; -> 243a8243a3jeq r1, 0x0, +4 ; -> 243a8243a4ldxdw r1, [r0-1]243a5ldxdw r2, [r0+7]243a6ldxdw r2, [r2+0]243a7callx r2243a8mov64 r1, r10243a9add64 r1, -0x3b0243aamov64 r2, 0x66243abcall fn_32b09243acldxdw r8, [r10-936]243adldxdw r6, [r10-944]243aeldxdw r4, [r10-952]243afstxdw [r4+8], r8243b0stxdw [r4+0], r6243b1exit243b2ldxdw r8, [r10-904]243b3ldxdw r1, [r10-720]243b4ldxdw r2, [r10-728]243b5ldxdw r3, [r2+0]243b6add64 r3, -0x1243b7stxdw [r2+0], r3243b8jne r3, 0x0, +3 ; -> 243bc243b9ldxdw r3, [r2+8]243baadd64 r3, -0x1243bbstxdw [r2+8], r3243bcldxdw r2, [r1+0]243bdadd64 r2, -0x1243bestxdw [r1+0], r2243bfldxdw r4, [r10-952]243c0jne r2, 0x0, +3 ; -> 243c4243c1ldxdw r2, [r1+8]243c2add64 r2, -0x1243c3stxdw [r1+8], r2243c4ldxdw r1, [r10-672]243c5ldxdw r2, [r10-680]243c6ldxdw r3, [r2+0]243c7add64 r3, -0x1243c8stxdw [r2+0], r3243c9jne r3, 0x0, +3 ; -> 243cd243caldxdw r3, [r2+8]243cbadd64 r3, -0x1243ccstxdw [r2+8], r3243cdldxdw r2, [r1+0]243ceadd64 r2, -0x1243cfstxdw [r1+0], r2243d0jne r2, 0x0, -34 ; -> 243af243d1ja -59 ; -> 24397243d2stxb [r10-896], r1243d3lddw r1, 0x1b3d30243d5stxdw [r10-448], r1243d6mov64 r1, r10243d7add64 r1, -0x10243d8stxdw [r10-432], r1243d9lddw r1, 0x1a96e0243dbstxdw [r10-8], r1243dcmov64 r1, r10243ddadd64 r1, -0x380243destxdw [r10-16], r1243dfstdw [r10-416], 0x0243e0stdw [r10-440], 0x1243e1stdw [r10-424], 0x1243e2mov64 r6, r10243e3add64 r6, -0x370243e4mov64 r2, r10243e5add64 r2, -0x1c0243e6mov64 r1, r6243e7call fn_342ee243e8mov64 r1, 0x15243e9mov64 r2, r6243eacall fn_01495243ebja -78 ; -> 2439e
// discriminator c2ab1c46684d5b2f ; handler fn_24323 -> try_accounts fn_13be6 -> logic fn_27215pub fn buy_exact_quote_in_v2(ctx, spendable_quote_in: u64, min_tokens_out: u64, allow_partial: Option<bool> /*byte 16, default false*/) -> Result<()> {msg!("Instruction: BuyExactQuoteInV2");let curve = &mut ctx.bonding_curve;require!(!curve.complete, 6005); // pc 27222 (curve struct byte 161)require!(min_tokens_out != 0, 6020); // pc 27223require!(spendable_quote_in != 0, 6041); // pc 27224require_valid_fee_recipient(global, fee_recipient, curve.is_mayhem)?; // fn_078ef (mayhem curves -> reserved_fee_recipients)if curve.quote_mint != Pubkey::default() {// token-quoted curve: CreateIdempotent ATAs (fn_029be) for the fee recipient, buyback recipient,// creator vault and user volume accumulator quote accounts; user pays rent} else {require!(quote_mint.key == WSOL, 6063); // pc 27501}let (protocol_bps, creator_bps, net, protocol_fee, creator_fee);if user.key == global.fee_exempt_user /*Global struct +0x288*/ { // pc 274adnet = spendable_quote_in; protocol_fee = 0; creator_fee = 0; // no-fee path} else {// fn_10820: market_cap = curve_market_cap(); CPI pump_fees::GetFeesWithQuoteMint(market_cap, quote_mint)// (fee_config today: flat lp 0 / protocol 95 / creator 30 at every tier)(protocol_bps, creator_bps) = fee_program_cpi(...);if global.creator_fee_override_enabled /*byte 1086*/ && curve.creator_fee_bps != 0 { creator_bps = curve.creator_fee_bps; }if curve.creator == Pubkey::default() { creator_bps = 0; }let total_bps = protocol_bps.checked_add(creator_bps)?;net = if total_bps == 0 { spendable_quote_in }else { (spendable_quote_in as u128 * 10_000 / (10_000 + total_bps) as u128) as u64 }; // floorrequire!(net != 0, 6041);protocol_fee = ceil_div(net * protocol_bps, 10_000); // fn_107c7creator_fee = if curve.creator != default { ceil_div(net * creator_bps, 10_000) } else { 0 };let total = net.saturating_add(protocol_fee).saturating_add(creator_fee);if total > spendable_quote_in { // rounding overshootnet -= total - spendable_quote_in; // fees are NOT recomputedrequire!(net != 0, 6042);}}// fn_1347e: constant product, one unit of quote held backlet mut tokens_out = ((net - 1) as u128 * curve.virtual_token_reserves as u128/ (curve.virtual_quote_reserves + net - 1) as u128) as u64;if tokens_out > curve.real_token_reserves && allow_partial { // pc 2760atokens_out = curve.real_token_reserves;net = quote_needed_for(tokens_out); // fn_13385protocol_fee = ceil(net*protocol_bps/1e4); creator_fee = ceil(net*creator_bps/1e4);require!(net + protocol_fee + creator_fee <= spendable_quote_in, 6002);}require!(tokens_out >= min_tokens_out, 6042); // pc 2761crequire!(tokens_out <= curve.real_token_reserves, 6021); // pc 27699// fn_134f5: virtual_token -= tokens_out; real_token -= tokens_out; virtual_quote += net; real_quote += netapply_buy(curve, tokens_out, net);// fn_1148a: token transfer_checked associated_base_bonding_curve -> associated_base_user, signed by PDA ["bonding-curve", mint]transfer_base(tokens_out);if creator_fee != 0 {if curve.cashback_enabled /*byte 163*/ {transfer_quote(user -> user_volume_accumulator (or its quote ATA), creator_fee); fn_0f055: record cashback} else {transfer_quote(user -> creator_vault (or associated_creator_vault), creator_fee); // fn_1234d}}transfer_quote(user -> bonding_curve (SOL) | associated_quote_bonding_curve (token), net); // fn_1229dlet buyback = if curve.is_mayhem /*byte 162*/ { 0 } else { protocol_fee * global.buyback_bps /*5000*/ / 10_000 }; // floor, fn_12780transfer_quote(user -> fee_recipient | associated_quote_fee_recipient, protocol_fee - buyback); // fn_122f5transfer_quote(user -> buyback_fee_recipient | associated_quote_buyback_fee_recipient, buyback); // fn_122f5// update global/user volume accumulators, emit TradeEvent (ix_name "buy_exact_quote_in"), check completionOk(())}
Replay model
The executable model the agent wrote. Every tally above comes from running it against mainnet.
const ALPH='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';function b58(hex){let n=BigInt('0x'+hex);let s='';while(n>0n){s=ALPH[Number(n%58n)]+s;n/=58n;}for(let i=0;i<hex.length&&hex.substr(i,2)==='00';i+=2)s='1'+s;return s;}// Global.reserved_fee_recipient + reserved_fee_recipients[7] (raw offsets 483, 516..739)const RESERVED=['e893141fb18e9f1574d810e178e19e30604e3175aa2e4a32dfc8600727d10709','3584536256094f912819127efa4e446b4333721793d13876f9aadbf3dc7d0b5f','6e75018220f942677003237b4d6b453759b4a5c690b59c35d9bb187a090cbd2a','33987a9ebb136799ab59925b13e5dc8b3081df005db427c1478fa46ff8c347a0','74e9543f3e37a2d046227addcb4e9c774c44258c43edf24aa8aae1f00214665b','da4c38cd6db7438f59b408bb9ec3b4ca9e8ad1f1f24653c499b5796c20dbf9b3','2ddd9eea3f39b372115c71847c1845cfa536c685074e030e44d021de3ef9e35c','4cb780f08ee2fee84bec446a577825da68d439fa8a5da3b0c5cff50f63f4546b'].map(b58);const WSOL='So11111111111111111111111111111111111111112';function model(ctx){const A=ctx.accounts;const spend=BigInt(ctx.args.spendable_quote_in);const PB=95n, CB=30n, BUYBACK_BPS=5000n;const tb=PB+CB;let net=spend*10000n/(10000n+tb);const ceil=(a,b)=>(a*b+9999n)/10000n;const pf=ceil(net,PB), cf=ceil(net,CB);let tot=net+pf+cf; if(tot>spend) net-=tot-spend;const isSol=A[2].pubkey===WSOL;const mayhem=RESERVED.includes(A[6].pubkey);const bb=mayhem?0n:pf*BUYBACK_BPS/10000n;const fr=pf-bb;const vtok=A[11].token.amount+73000000000000n;let vq;if(isSol){ vq=A[10].lamports-1493520n+30000000000n; }else { vq=A[12].token.amount+550724007602n; }const tokens=(net-1n)*vtok/(vq+net-1n);const L={},T={};T[11]=-tokens; T[14]=tokens;if(isSol){L[10]=net;L[6]=fr;L[8]=bb;L[16]=cf;}else{T[12]=net;T[7]=fr;T[9]=bb;T[17]=cf;}return {lamports:L,tokens:T};}
Accounts
- 0global
- 1base_mint
- 2quote_mint
- 3base_token_program
- 4quote_token_program
- 5associated_token_program
- 6fee_recipientwritten
- 7associated_quote_fee_recipientwritten
- 8buyback_fee_recipientwritten
- 9associated_quote_buyback_fee_recipientwritten
- 10bonding_curvewritten
- 11associated_base_bonding_curvewritten
- 12associated_quote_bonding_curvewritten
- 13usersigns, written
- 14associated_base_userwritten
- 15associated_quote_userwritten
- 16creator_vaultwritten
- 17associated_creator_vaultwritten
- 18sharing_config
- 19global_volume_accumulator
- 20user_volume_accumulatorwritten
- 21associated_user_volume_accumulatorwritten
- 22fee_config
- 23fee_program
- 24system_program
- 25event_authority
- 26program
args: spendable_quote_in: u64, min_tokens_out: u64
program 6EF8rr…BEwF6P