feat: support Pump.fun V2 (Mayhem Mode) and update protocol structures for Nov 11 breaking changes

This commit is contained in:
ysq
2025-11-09 23:59:56 +08:00
parent 9e4f71dbb2
commit 6e3d2c23d1
3 changed files with 142 additions and 41 deletions
@@ -22,20 +22,15 @@ pub struct PumpFunCreateTokenEvent {
pub real_token_reserves: u64,
pub token_total_supply: u64,
#[borsh(skip)]
pub token_program: Pubkey,
#[borsh(skip)]
pub is_mayhem_mode: bool,
#[borsh(skip)]
pub mint_authority: Pubkey,
#[borsh(skip)]
pub associated_bonding_curve: Pubkey,
}
pub const PUMPFUN_CREATE_TOKEN_EVENT_LOG_SIZE: usize = 257;
pub fn pumpfun_create_token_event_log_decode(data: &[u8]) -> Option<PumpFunCreateTokenEvent> {
if data.len() < PUMPFUN_CREATE_TOKEN_EVENT_LOG_SIZE {
return None;
}
borsh::from_slice::<PumpFunCreateTokenEvent>(&data[..PUMPFUN_CREATE_TOKEN_EVENT_LOG_SIZE]).ok()
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct PumpFunCreateV2TokenEvent {
#[borsh(skip)]
@@ -60,13 +55,127 @@ pub struct PumpFunCreateV2TokenEvent {
pub associated_bonding_curve: Pubkey,
}
pub const PUMPFUN_CREATE_V2_TOKEN_EVENT_LOG_SIZE: usize = 257 + 32 + 1;
pub fn pumpfun_create_v2_token_event_log_decode(data: &[u8]) -> Option<PumpFunCreateV2TokenEvent> {
if data.len() < PUMPFUN_CREATE_V2_TOKEN_EVENT_LOG_SIZE {
let mut offset = 0;
// 解析 name 字符串: [长度(4字节 u32)][字符串内容]
if data.len() < offset + 4 {
return None;
}
borsh::from_slice::<PumpFunCreateV2TokenEvent>(&data[..PUMPFUN_CREATE_V2_TOKEN_EVENT_LOG_SIZE]).ok()
let name_len = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
offset += 4;
if data.len() < offset + name_len {
return None;
}
let name = String::from_utf8(data[offset..offset + name_len].to_vec()).ok()?;
offset += name_len;
// 解析 symbol 字符串
if data.len() < offset + 4 {
return None;
}
let symbol_len = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
offset += 4;
if data.len() < offset + symbol_len {
return None;
}
let symbol = String::from_utf8(data[offset..offset + symbol_len].to_vec()).ok()?;
offset += symbol_len;
// 解析 uri 字符串
if data.len() < offset + 4 {
return None;
}
let uri_len = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
offset += 4;
if data.len() < offset + uri_len {
return None;
}
let uri = String::from_utf8(data[offset..offset + uri_len].to_vec()).ok()?;
offset += uri_len;
// 解析 Pubkey 字段 (每个32字节)
if data.len() < offset + 32 {
return None;
}
let mint = Pubkey::new_from_array(data[offset..offset + 32].try_into().ok()?);
offset += 32;
if data.len() < offset + 32 {
return None;
}
let bonding_curve = Pubkey::new_from_array(data[offset..offset + 32].try_into().ok()?);
offset += 32;
if data.len() < offset + 32 {
return None;
}
let user = Pubkey::new_from_array(data[offset..offset + 32].try_into().ok()?);
offset += 32;
if data.len() < offset + 32 {
return None;
}
let creator = Pubkey::new_from_array(data[offset..offset + 32].try_into().ok()?);
offset += 32;
// 解析数值字段
if data.len() < offset + 8 {
return None;
}
let timestamp = i64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
offset += 8;
if data.len() < offset + 8 {
return None;
}
let virtual_token_reserves = u64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
offset += 8;
if data.len() < offset + 8 {
return None;
}
let virtual_sol_reserves = u64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
offset += 8;
if data.len() < offset + 8 {
return None;
}
let real_token_reserves = u64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
offset += 8;
if data.len() < offset + 8 {
return None;
}
let token_total_supply = u64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
offset += 8;
// 如果数据长度足够,解析 V2 版本的额外字段: token_program (32字节) + is_mayhem_mode (1字节)
let (token_program, is_mayhem_mode) = if data.len() >= offset + 33 {
let token_program = Pubkey::new_from_array(data[offset..offset + 32].try_into().ok()?);
let is_mayhem_mode = data[offset + 32] == 1;
(token_program, is_mayhem_mode)
} else {
(Pubkey::default(), false)
};
Some(PumpFunCreateV2TokenEvent {
name,
symbol,
uri,
mint,
bonding_curve,
user,
creator,
timestamp,
virtual_token_reserves,
virtual_sol_reserves,
real_token_reserves,
token_total_supply,
token_program,
is_mayhem_mode,
..Default::default()
})
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]