fix(pump): restore 26-byte legacy buy instruction data encoding
The refactored ix data encoder was producing 25-byte buy instructions (1-byte track_volume), but the on-chain Pump program expects Anchor's 2-byte Option<bool> encoding (option tag + value), totaling 26 bytes. The 1-byte shortfall caused instruction data under-read that manifested as error 0xbbf (ConstraintOwner) for all legacy buy/buy_exact_sol_in. Restore the 2-byte encoding: option tag (1u8) followed by the cashback flag as the bool value, matching the pre-refactoring inline encoder. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
ce8fb99626
commit
b49c1c803e
@@ -12,7 +12,7 @@ use crate::{
|
|||||||
instruction::pumpfun_ix_data::{
|
instruction::pumpfun_ix_data::{
|
||||||
encode_pumpfun_buy_exact_quote_in_v2_ix_data, encode_pumpfun_buy_exact_sol_in_ix_data,
|
encode_pumpfun_buy_exact_quote_in_v2_ix_data, encode_pumpfun_buy_exact_sol_in_ix_data,
|
||||||
encode_pumpfun_buy_ix_data, encode_pumpfun_buy_v2_ix_data,
|
encode_pumpfun_buy_ix_data, encode_pumpfun_buy_v2_ix_data,
|
||||||
encode_pumpfun_sell_ix_data, encode_pumpfun_sell_v2_ix_data, TRACK_VOLUME_TRUE,
|
encode_pumpfun_sell_ix_data, encode_pumpfun_sell_v2_ix_data,
|
||||||
},
|
},
|
||||||
instruction::utils::pumpfun::{
|
instruction::utils::pumpfun::{
|
||||||
accounts, get_bonding_curve_pda, get_bonding_curve_v2_pda,
|
accounts, get_bonding_curve_pda, get_bonding_curve_v2_pda,
|
||||||
@@ -230,15 +230,16 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Legacy buy path ──
|
// ── Legacy buy path ──
|
||||||
|
let track_volume_val = if bonding_curve.is_cashback_coin { 1u8 } else { 0u8 };
|
||||||
let buy_data = if params.use_exact_sol_amount.unwrap_or(true) {
|
let buy_data = if params.use_exact_sol_amount.unwrap_or(true) {
|
||||||
let min_tokens_out = calculate_with_slippage_sell(buy_token_amount, slippage_bp);
|
let min_tokens_out = calculate_with_slippage_sell(buy_token_amount, slippage_bp);
|
||||||
encode_pumpfun_buy_exact_sol_in_ix_data(
|
encode_pumpfun_buy_exact_sol_in_ix_data(
|
||||||
lamports_in,
|
lamports_in,
|
||||||
min_tokens_out,
|
min_tokens_out,
|
||||||
TRACK_VOLUME_TRUE,
|
track_volume_val,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
encode_pumpfun_buy_ix_data(buy_token_amount, max_sol_cost, TRACK_VOLUME_TRUE)
|
encode_pumpfun_buy_ix_data(buy_token_amount, max_sol_cost, track_volume_val)
|
||||||
};
|
};
|
||||||
|
|
||||||
let bonding_curve_v2 = get_bonding_curve_v2_pda(¶ms.output_mint).ok_or_else(|| {
|
let bonding_curve_v2 = get_bonding_curve_v2_pda(¶ms.output_mint).ok_or_else(|| {
|
||||||
|
|||||||
@@ -7,20 +7,22 @@ use crate::instruction::utils::pumpfun::{
|
|||||||
BUY_V2_DISCRIMINATOR, SELL_DISCRIMINATOR, SELL_V2_DISCRIMINATOR,
|
BUY_V2_DISCRIMINATOR, SELL_DISCRIMINATOR, SELL_V2_DISCRIMINATOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 与官方 `getBuyInstructionInternal` 一致:`track_volume = true`。
|
/// 与官方 `getBuyInstructionInternal` 对齐:`OptionBool` 在 ix 中为 1 字节 option tag + 1 字节值。
|
||||||
pub const TRACK_VOLUME_TRUE: u8 = 1;
|
/// `track_volume` 在调用侧组合为 `(1u8, cashback as u8)`(Option tag + value),共 26 字节 ix data。
|
||||||
|
pub const TRACK_VOLUME_OPTION_TAG: u8 = 1;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encode_pumpfun_buy_ix_data(
|
pub fn encode_pumpfun_buy_ix_data(
|
||||||
token_amount: u64,
|
token_amount: u64,
|
||||||
max_sol_cost: u64,
|
max_sol_cost: u64,
|
||||||
track_volume: u8,
|
track_volume_val: u8,
|
||||||
) -> [u8; 25] {
|
) -> [u8; 26] {
|
||||||
let mut d = [0u8; 25];
|
let mut d = [0u8; 26];
|
||||||
d[..8].copy_from_slice(&BUY_DISCRIMINATOR);
|
d[..8].copy_from_slice(&BUY_DISCRIMINATOR);
|
||||||
d[8..16].copy_from_slice(&token_amount.to_le_bytes());
|
d[8..16].copy_from_slice(&token_amount.to_le_bytes());
|
||||||
d[16..24].copy_from_slice(&max_sol_cost.to_le_bytes());
|
d[16..24].copy_from_slice(&max_sol_cost.to_le_bytes());
|
||||||
d[24] = track_volume;
|
d[24] = TRACK_VOLUME_OPTION_TAG;
|
||||||
|
d[25] = track_volume_val;
|
||||||
d
|
d
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,13 +30,14 @@ pub fn encode_pumpfun_buy_ix_data(
|
|||||||
pub fn encode_pumpfun_buy_exact_sol_in_ix_data(
|
pub fn encode_pumpfun_buy_exact_sol_in_ix_data(
|
||||||
spendable_sol_in: u64,
|
spendable_sol_in: u64,
|
||||||
min_tokens_out: u64,
|
min_tokens_out: u64,
|
||||||
track_volume: u8,
|
track_volume_val: u8,
|
||||||
) -> [u8; 25] {
|
) -> [u8; 26] {
|
||||||
let mut d = [0u8; 25];
|
let mut d = [0u8; 26];
|
||||||
d[..8].copy_from_slice(&BUY_EXACT_SOL_IN_DISCRIMINATOR);
|
d[..8].copy_from_slice(&BUY_EXACT_SOL_IN_DISCRIMINATOR);
|
||||||
d[8..16].copy_from_slice(&spendable_sol_in.to_le_bytes());
|
d[8..16].copy_from_slice(&spendable_sol_in.to_le_bytes());
|
||||||
d[16..24].copy_from_slice(&min_tokens_out.to_le_bytes());
|
d[16..24].copy_from_slice(&min_tokens_out.to_le_bytes());
|
||||||
d[24] = track_volume;
|
d[24] = TRACK_VOLUME_OPTION_TAG;
|
||||||
|
d[25] = track_volume_val;
|
||||||
d
|
d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user