use super::program_ids;
use super::utils::*;
use crate::core::events::*;
use solana_sdk::{pubkey::Pubkey, signature::Signature};
pub mod discriminators {
pub const SWAP_LOG: [u8; 8] = [27, 60, 21, 213, 138, 170, 187, 147];
pub const SWAP2_LOG: [u8; 8] = [189, 66, 51, 168, 38, 80, 117, 153];
pub const CREATE_POSITION_LOG: [u8; 8] = [156, 15, 119, 198, 29, 181, 221, 55];
pub const CLOSE_POSITION_LOG: [u8; 8] = [20, 145, 144, 68, 143, 142, 214, 178];
pub const ADD_LIQUIDITY_LOG: [u8; 8] = [175, 242, 8, 157, 30, 247, 185, 169];
pub const REMOVE_LIQUIDITY_LOG: [u8; 8] = [87, 46, 88, 98, 175, 96, 34, 91];
}
pub const PROGRAM_ID_PUBKEY: Pubkey = program_ids::METEORA_DAMM_V2_PROGRAM_ID;
#[allow(unused_variables)]
pub fn parse_instruction(
instruction_data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
grpc_recv_us: i64,
) -> Option<DexEvent> {
if instruction_data.len() < 8 {
return None;
}
let discriminator: [u8; 8] = instruction_data[0..8].try_into().ok()?;
let data = &instruction_data[8..];
if instruction_data.len() < 16 {
return None;
}
let cpi_discriminator: [u8; 8] = instruction_data[8..16].try_into().ok()?;
let cpi_data = &instruction_data[16..];
match cpi_discriminator {
discriminators::SWAP_LOG => {
return parse_swap_log_instruction(
cpi_data,
accounts,
signature,
slot,
tx_index,
block_time_us,
grpc_recv_us,
)
}
discriminators::SWAP2_LOG => {
return parse_swap2_log_instruction(
cpi_data,
accounts,
signature,
slot,
tx_index,
block_time_us,
grpc_recv_us,
)
}
discriminators::CREATE_POSITION_LOG => {
return parse_create_position_log_instruction(
cpi_data,
accounts,
signature,
slot,
tx_index,
block_time_us,
grpc_recv_us,
);
}
discriminators::CLOSE_POSITION_LOG => {
return parse_close_position_log_instruction(
data,
accounts,
signature,
slot,
tx_index,
block_time_us,
grpc_recv_us,
);
}
discriminators::ADD_LIQUIDITY_LOG => {
return parse_add_liquidity_log_instruction(
cpi_data,
accounts,
signature,
slot,
tx_index,
block_time_us,
grpc_recv_us,
);
}
discriminators::REMOVE_LIQUIDITY_LOG => {
return parse_remove_liquidity_log_instruction(
cpi_data,
accounts,
signature,
slot,
tx_index,
block_time_us,
grpc_recv_us,
);
}
_ => None,
}
}
#[allow(unused_variables)]
fn parse_swap_log_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
rpc_recv_us: i64,
) -> Option<DexEvent> {
let mut offset = 0;
let pool = read_pubkey(data, offset)?;
offset += 32;
let trade_direction = read_u8(data, offset)?;
offset += 1;
let has_referral = read_bool(data, offset)?;
offset += 1;
let amount_in = read_u64_le(data, offset)?;
offset += 8;
let min_amount_out = read_u64_le(data, offset)?;
offset += 8;
let output_amount = read_u64_le(data, offset)?;
offset += 8;
let next_sqrt_price = read_u128_le(data, offset)?;
offset += 16;
let lp_fee = read_u64_le(data, offset)?;
offset += 8;
let protocol_fee = read_u64_le(data, offset)?;
offset += 8;
let partner_fee = read_u64_le(data, offset)?;
offset += 8;
let referral_fee = read_u64_le(data, offset)?;
offset += 8;
let actual_amount_in = read_u64_le(data, offset)?;
offset += 8;
let current_timestamp = read_u64_le(data, offset)?;
let metadata =
create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), rpc_recv_us);
Some(DexEvent::MeteoraDammV2Swap(MeteoraDammV2SwapEvent {
metadata,
pool,
trade_direction,
has_referral,
amount_in,
minimum_amount_out: min_amount_out,
output_amount,
next_sqrt_price,
lp_fee,
protocol_fee,
partner_fee,
referral_fee,
actual_amount_in,
current_timestamp,
..Default::default()
}))
}
#[allow(unused_variables)]
fn parse_swap2_log_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
rpc_recv_us: i64,
) -> Option<DexEvent> {
let mut offset = 0;
let pool = read_pubkey(data, offset)?;
offset += 32;
let trade_direction = read_u8(data, offset)?;
offset += 1;
let _collect_fee_mode = read_u8(data, offset)?;
offset += 1;
let has_referral = read_bool(data, offset)?;
offset += 1;
let amount_0 = read_u64_le(data, offset)?;
offset += 8;
let amount_1 = read_u64_le(data, offset)?;
offset += 8;
let swap_mode = read_u8(data, offset)?;
offset += 1;
let included_fee_input_amount = read_u64_le(data, offset)?;
offset += 8;
let _excluded_fee_input_amount = read_u64_le(data, offset)?;
offset += 8;
let _amount_left = read_u64_le(data, offset)?;
offset += 8;
let output_amount = read_u64_le(data, offset)?;
offset += 8;
let next_sqrt_price = read_u128_le(data, offset)?;
offset += 16;
let lp_fee = read_u64_le(data, offset)?;
offset += 8;
let protocol_fee = read_u64_le(data, offset)?;
offset += 8;
let referral_fee = read_u64_le(data, offset)?;
offset += 8;
let _quote_reserve_amount = read_u64_le(data, offset)?;
offset += 8;
let _migration_threshold = read_u64_le(data, offset)?;
offset += 8;
let current_timestamp = read_u64_le(data, offset)?;
let metadata =
create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), rpc_recv_us);
let (amount_in, minimum_amount_out) = if swap_mode == 0 {
(amount_0, amount_1)
} else {
(amount_1, amount_0)
};
let actual_amount_in = included_fee_input_amount;
Some(DexEvent::MeteoraDammV2Swap(MeteoraDammV2SwapEvent {
metadata,
pool,
trade_direction,
has_referral,
amount_in,
minimum_amount_out,
output_amount,
next_sqrt_price,
lp_fee,
protocol_fee,
partner_fee: 0, referral_fee,
actual_amount_in,
current_timestamp,
..Default::default()
}))
}
#[allow(unused_variables)]
fn parse_create_position_log_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
rpc_recv_us: i64,
) -> Option<DexEvent> {
let mut offset = 0;
let pool = read_pubkey(data, offset)?;
offset += 32;
let owner = read_pubkey(data, offset)?;
offset += 32;
let position = read_pubkey(data, offset)?;
offset += 32;
let position_nft_mint = read_pubkey(data, offset)?;
let metadata =
create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), rpc_recv_us);
Some(DexEvent::MeteoraDammV2CreatePosition(MeteoraDammV2CreatePositionEvent {
metadata,
pool,
owner,
position,
position_nft_mint,
}))
}
#[allow(unused_variables)]
fn parse_close_position_log_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
rpc_recv_us: i64,
) -> Option<DexEvent> {
let mut offset = 0;
let pool = read_pubkey(data, offset)?;
offset += 32;
let owner = read_pubkey(data, offset)?;
offset += 32;
let position = read_pubkey(data, offset)?;
offset += 32;
let position_nft_mint = read_pubkey(data, offset)?;
let metadata =
create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), rpc_recv_us);
Some(DexEvent::MeteoraDammV2ClosePosition(MeteoraDammV2ClosePositionEvent {
metadata,
pool,
owner,
position,
position_nft_mint,
}))
}
#[allow(unused_variables)]
fn parse_add_liquidity_log_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
rpc_recv_us: i64,
) -> Option<DexEvent> {
let mut offset = 0;
let pool = read_pubkey(data, offset)?;
offset += 32;
let position = read_pubkey(data, offset)?;
offset += 32;
let owner = read_pubkey(data, offset)?;
offset += 32;
let liquidity_delta = read_u128_le(data, offset)?;
offset += 16;
let token_a_amount_threshold = read_u64_le(data, offset)?;
offset += 8;
let token_b_amount_threshold = read_u64_le(data, offset)?;
offset += 8;
let token_a_amount = read_u64_le(data, offset)?;
offset += 8;
let token_b_amount = read_u64_le(data, offset)?;
offset += 8;
let total_amount_a = read_u64_le(data, offset)?;
offset += 8;
let total_amount_b = read_u64_le(data, offset)?;
let metadata =
create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), rpc_recv_us);
Some(DexEvent::MeteoraDammV2AddLiquidity(MeteoraDammV2AddLiquidityEvent {
metadata,
pool,
position,
owner,
liquidity_delta,
token_a_amount_threshold,
token_b_amount_threshold,
token_a_amount,
token_b_amount,
total_amount_a,
total_amount_b,
}))
}
#[allow(unused_variables)]
fn parse_remove_liquidity_log_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
rpc_recv_us: i64,
) -> Option<DexEvent> {
let mut offset = 0;
let pool = read_pubkey(data, offset)?;
offset += 32;
let position = read_pubkey(data, offset)?;
offset += 32;
let owner = read_pubkey(data, offset)?;
offset += 32;
let liquidity_delta = read_u128_le(data, offset)?;
offset += 16;
let token_a_amount_threshold = read_u64_le(data, offset)?;
offset += 8;
let token_b_amount_threshold = read_u64_le(data, offset)?;
offset += 8;
let token_a_amount = read_u64_le(data, offset)?;
offset += 8;
let token_b_amount = read_u64_le(data, offset)?;
let metadata =
create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), rpc_recv_us);
Some(DexEvent::MeteoraDammV2RemoveLiquidity(MeteoraDammV2RemoveLiquidityEvent {
metadata,
pool,
position,
owner,
liquidity_delta,
token_a_amount_threshold,
token_b_amount_threshold,
token_a_amount,
token_b_amount,
}))
}