use crate::core::events::*;
use crate::instr::inner_common::*;
use solana_sdk::pubkey::Pubkey;
pub mod discriminators {
pub const SWAP: [u8; 16] =
[228, 69, 165, 46, 81, 203, 154, 29, 27, 60, 21, 213, 138, 170, 187, 147];
pub const SWAP2: [u8; 16] =
[228, 69, 165, 46, 81, 203, 154, 29, 189, 66, 51, 168, 38, 80, 117, 153];
pub const ADD_LIQUIDITY: [u8; 16] =
[228, 69, 165, 46, 81, 203, 154, 29, 175, 242, 8, 157, 30, 247, 185, 169];
pub const REMOVE_LIQUIDITY: [u8; 16] =
[228, 69, 165, 46, 81, 203, 154, 29, 87, 46, 88, 98, 175, 96, 34, 91];
pub const CREATE_POSITION: [u8; 16] =
[228, 69, 165, 46, 81, 203, 154, 29, 156, 15, 119, 198, 29, 181, 221, 55];
pub const CLOSE_POSITION: [u8; 16] =
[228, 69, 165, 46, 81, 203, 154, 29, 20, 145, 144, 68, 143, 142, 214, 178];
}
#[inline]
pub fn parse(disc: &[u8; 16], data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
match disc {
&discriminators::SWAP => parse_swap(data, metadata),
&discriminators::SWAP2 => parse_swap2(data, metadata),
&discriminators::ADD_LIQUIDITY => parse_add_liquidity(data, metadata),
&discriminators::REMOVE_LIQUIDITY => parse_remove_liquidity(data, metadata),
&discriminators::CREATE_POSITION => parse_create_position(data, metadata),
&discriminators::CLOSE_POSITION => parse_close_position(data, metadata),
_ => None,
}
}
#[inline(always)]
fn parse_swap(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
#[cfg(feature = "parse-borsh")]
{
parse_swap_borsh(data, metadata)
}
#[cfg(feature = "parse-zero-copy")]
{
parse_swap_zero_copy(data, metadata)
}
}
#[cfg(feature = "parse-borsh")]
#[inline(always)]
fn parse_swap_borsh(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const SWAP_EVENT_SIZE: usize = 32 + 8 + 8;
if data.len() < SWAP_EVENT_SIZE {
return None;
}
let event = borsh::from_slice::<MeteoraDammV2SwapEvent>(&data[..SWAP_EVENT_SIZE]).ok()?;
Some(DexEvent::MeteoraDammV2Swap(MeteoraDammV2SwapEvent { metadata, ..event }))
}
#[cfg(feature = "parse-zero-copy")]
#[inline(always)]
fn parse_swap_zero_copy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
unsafe {
if !check_length(data, 32 + 8 + 8) {
return None;
}
let pool = read_pubkey_unchecked(data, 0);
let amount_in = read_u64_unchecked(data, 32);
let output_amount = read_u64_unchecked(data, 40);
Some(DexEvent::MeteoraDammV2Swap(MeteoraDammV2SwapEvent {
metadata,
pool,
amount_in,
output_amount,
..Default::default()
}))
}
}
#[inline(always)]
fn parse_swap2(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
#[cfg(feature = "parse-borsh")]
{
parse_swap2_borsh(data, metadata)
}
#[cfg(feature = "parse-zero-copy")]
{
parse_swap2_zero_copy(data, metadata)
}
}
#[cfg(feature = "parse-borsh")]
#[inline(always)]
fn parse_swap2_borsh(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const SWAP2_EVENT_MIN_SIZE: usize = 177;
if data.len() < SWAP2_EVENT_MIN_SIZE {
return None;
}
let mut offset = 0;
unsafe {
let pool = read_pubkey_unchecked(data, offset);
offset += 32;
let _config = read_pubkey_unchecked(data, offset);
offset += 32;
let trade_direction = read_u8_unchecked(data, offset);
offset += 1;
let has_referral = read_bool_unchecked(data, offset);
offset += 1;
let amount_0 = read_u64_unchecked(data, offset);
offset += 8;
let amount_1 = read_u64_unchecked(data, offset);
offset += 8;
let swap_mode = read_u8_unchecked(data, offset);
offset += 1;
let included_fee_input_amount = read_u64_unchecked(data, offset);
offset += 8;
let _excluded_fee_input_amount = read_u64_unchecked(data, offset);
offset += 8;
let _amount_left = read_u64_unchecked(data, offset);
offset += 8;
let output_amount = read_u64_unchecked(data, offset);
offset += 8;
let next_sqrt_price = read_u128_unchecked(data, offset);
offset += 16;
let lp_fee = read_u64_unchecked(data, offset);
offset += 8;
let protocol_fee = read_u64_unchecked(data, offset);
offset += 8;
let referral_fee = read_u64_unchecked(data, offset);
offset += 8;
let _quote_reserve_amount = read_u64_unchecked(data, offset);
offset += 8;
let _migration_threshold = read_u64_unchecked(data, offset);
offset += 8;
let current_timestamp = read_u64_unchecked(data, offset);
let (amount_in, minimum_amount_out) =
if swap_mode == 0 { (amount_0, amount_1) } else { (amount_1, amount_0) };
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: included_fee_input_amount,
current_timestamp,
..Default::default()
}))
}
}
#[cfg(feature = "parse-zero-copy")]
#[inline(always)]
fn parse_swap2_zero_copy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const SWAP2_EVENT_MIN_SIZE: usize = 177;
unsafe {
if !check_length(data, SWAP2_EVENT_MIN_SIZE) {
return None;
}
let pool = read_pubkey_unchecked(data, 0);
let trade_direction = read_u8_unchecked(data, 64);
let has_referral = read_bool_unchecked(data, 65);
let amount_0 = read_u64_unchecked(data, 66);
let amount_1 = read_u64_unchecked(data, 74);
let swap_mode = read_u8_unchecked(data, 82);
let included_fee_input_amount = read_u64_unchecked(data, 83);
let output_amount = read_u64_unchecked(data, 107);
let next_sqrt_price = read_u128_unchecked(data, 115);
let lp_fee = read_u64_unchecked(data, 131);
let protocol_fee = read_u64_unchecked(data, 139);
let referral_fee = read_u64_unchecked(data, 147);
let current_timestamp = read_u64_unchecked(data, 169);
let (amount_in, minimum_amount_out) =
if swap_mode == 0 { (amount_0, amount_1) } else { (amount_1, amount_0) };
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: included_fee_input_amount,
current_timestamp,
..Default::default()
}))
}
}
#[inline(always)]
fn parse_add_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
#[cfg(feature = "parse-borsh")]
{
parse_add_liquidity_borsh(data, metadata)
}
#[cfg(feature = "parse-zero-copy")]
{
parse_add_liquidity_zero_copy(data, metadata)
}
}
#[cfg(feature = "parse-borsh")]
#[inline(always)]
fn parse_add_liquidity_borsh(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const ADD_LIQUIDITY_EVENT_SIZE: usize = 32 + 32 + 32 + 8 + 8;
if data.len() < ADD_LIQUIDITY_EVENT_SIZE {
return None;
}
let event =
borsh::from_slice::<MeteoraDammV2AddLiquidityEvent>(&data[..ADD_LIQUIDITY_EVENT_SIZE])
.ok()?;
Some(DexEvent::MeteoraDammV2AddLiquidity(MeteoraDammV2AddLiquidityEvent {
metadata,
..event
}))
}
#[cfg(feature = "parse-zero-copy")]
#[inline(always)]
fn parse_add_liquidity_zero_copy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
unsafe {
if !check_length(data, 32 + 32 + 32 + 8 + 8) {
return None;
}
let pool = read_pubkey_unchecked(data, 0);
let position = read_pubkey_unchecked(data, 32);
let owner = read_pubkey_unchecked(data, 64);
let token_a_amount = read_u64_unchecked(data, 96);
let token_b_amount = read_u64_unchecked(data, 104);
Some(DexEvent::MeteoraDammV2AddLiquidity(MeteoraDammV2AddLiquidityEvent {
metadata,
pool,
position,
owner,
token_a_amount,
token_b_amount,
liquidity_delta: 0,
token_a_amount_threshold: 0,
token_b_amount_threshold: 0,
total_amount_a: 0,
total_amount_b: 0,
}))
}
}
#[inline(always)]
fn parse_remove_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
#[cfg(feature = "parse-borsh")]
{
parse_remove_liquidity_borsh(data, metadata)
}
#[cfg(feature = "parse-zero-copy")]
{
parse_remove_liquidity_zero_copy(data, metadata)
}
}
#[cfg(feature = "parse-borsh")]
#[inline(always)]
fn parse_remove_liquidity_borsh(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const REMOVE_LIQUIDITY_EVENT_SIZE: usize = 32 + 32 + 32 + 8 + 8;
if data.len() < REMOVE_LIQUIDITY_EVENT_SIZE {
return None;
}
let event = borsh::from_slice::<MeteoraDammV2RemoveLiquidityEvent>(
&data[..REMOVE_LIQUIDITY_EVENT_SIZE],
)
.ok()?;
Some(DexEvent::MeteoraDammV2RemoveLiquidity(MeteoraDammV2RemoveLiquidityEvent {
metadata,
..event
}))
}
#[cfg(feature = "parse-zero-copy")]
#[inline(always)]
fn parse_remove_liquidity_zero_copy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
unsafe {
if !check_length(data, 32 + 32 + 32 + 8 + 8) {
return None;
}
let pool = read_pubkey_unchecked(data, 0);
let position = read_pubkey_unchecked(data, 32);
let owner = read_pubkey_unchecked(data, 64);
let token_a_amount = read_u64_unchecked(data, 96);
let token_b_amount = read_u64_unchecked(data, 104);
Some(DexEvent::MeteoraDammV2RemoveLiquidity(MeteoraDammV2RemoveLiquidityEvent {
metadata,
pool,
position,
owner,
token_a_amount,
token_b_amount,
liquidity_delta: 0,
token_a_amount_threshold: 0,
token_b_amount_threshold: 0,
}))
}
}
#[inline(always)]
fn parse_create_position(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
#[cfg(feature = "parse-borsh")]
{
parse_create_position_borsh(data, metadata)
}
#[cfg(feature = "parse-zero-copy")]
{
parse_create_position_zero_copy(data, metadata)
}
}
#[cfg(feature = "parse-borsh")]
#[inline(always)]
fn parse_create_position_borsh(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const CREATE_POSITION_EVENT_SIZE: usize = 32 + 32 + 32 + 32;
if data.len() < CREATE_POSITION_EVENT_SIZE {
return None;
}
let event = borsh::from_slice::<MeteoraDammV2CreatePositionEvent>(
&data[..CREATE_POSITION_EVENT_SIZE],
)
.ok()?;
Some(DexEvent::MeteoraDammV2CreatePosition(MeteoraDammV2CreatePositionEvent {
metadata,
..event
}))
}
#[cfg(feature = "parse-zero-copy")]
#[inline(always)]
fn parse_create_position_zero_copy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
unsafe {
if !check_length(data, 32 + 32 + 32 + 32) {
return None;
}
let pool = read_pubkey_unchecked(data, 0);
let owner = read_pubkey_unchecked(data, 32);
let position = read_pubkey_unchecked(data, 64);
let position_nft_mint = read_pubkey_unchecked(data, 96);
Some(DexEvent::MeteoraDammV2CreatePosition(MeteoraDammV2CreatePositionEvent {
metadata,
pool,
owner,
position,
position_nft_mint,
}))
}
}
#[inline(always)]
fn parse_close_position(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
#[cfg(feature = "parse-borsh")]
{
parse_close_position_borsh(data, metadata)
}
#[cfg(feature = "parse-zero-copy")]
{
parse_close_position_zero_copy(data, metadata)
}
}
#[cfg(feature = "parse-borsh")]
#[inline(always)]
fn parse_close_position_borsh(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
const CLOSE_POSITION_EVENT_SIZE: usize = 32 + 32 + 32 + 32;
if data.len() < CLOSE_POSITION_EVENT_SIZE {
return None;
}
let event = borsh::from_slice::<MeteoraDammV2ClosePositionEvent>(
&data[..CLOSE_POSITION_EVENT_SIZE],
)
.ok()?;
Some(DexEvent::MeteoraDammV2ClosePosition(MeteoraDammV2ClosePositionEvent {
metadata,
..event
}))
}
#[cfg(feature = "parse-zero-copy")]
#[inline(always)]
fn parse_close_position_zero_copy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
unsafe {
if !check_length(data, 32 + 32 + 32 + 32) {
return None;
}
let pool = read_pubkey_unchecked(data, 0);
let owner = read_pubkey_unchecked(data, 32);
let position = read_pubkey_unchecked(data, 64);
let position_nft_mint = read_pubkey_unchecked(data, 96);
Some(DexEvent::MeteoraDammV2ClosePosition(MeteoraDammV2ClosePositionEvent {
metadata,
pool,
owner,
position,
position_nft_mint,
}))
}
}