This commit is contained in:
2026-06-09 10:13:03 +02:00
parent f2ea1a392f
commit bfdb2e69ae
41 changed files with 4485 additions and 1124 deletions

View File

@@ -523,43 +523,16 @@ impl DexDecodeService {
transaction_id: i64,
discriminator_hex: &str,
) -> Result<(), crate::Error> {
match self.database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let delete_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE transaction_id = ?
AND protocol_name = 'raydium_clmm'
AND event_kind = 'raydium_clmm.instruction_audit'
AND (
json_extract(payload_json, '$.discriminatorHex') = ?
OR json_extract(payload_json, '$.discriminator_hex') = ?
OR json_extract(payload_json, '$.instructionDiscriminatorHex') = ?
OR json_extract(payload_json, '$.instruction_discriminator_hex') = ?
OR json_extract(payload_json, '$.anchorEventDiscriminatorHex') = ?
OR json_extract(payload_json, '$.anchor_event_discriminator_hex') = ?
)
"#,
)
.bind(transaction_id)
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.execute(pool)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot delete Raydium CLMM residual instruction audit '{}': {}",
discriminator_hex, error
)));
},
}
},
let delete_result =
crate::query_dex_decoded_events_delete_raydium_clmm_instruction_audit_by_discriminator(
self.database.as_ref(),
transaction_id,
discriminator_hex,
)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => return Err(error),
}
}
@@ -706,88 +679,18 @@ WHERE transaction_id = ?
Some(audit_event_kind) => audit_event_kind,
None => return Ok(()),
};
match self.database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let unlink_result = sqlx::query(
r#"
UPDATE k_sol_instruction_observations
SET decoded_event_id = NULL
WHERE decoded_event_id IN (
SELECT id
FROM k_sol_dex_decoded_events
WHERE transaction_id = ?
AND protocol_name = ?
AND event_kind = ?
AND (
json_extract(payload_json, '$.discriminatorHex') = ?
OR json_extract(payload_json, '$.discriminator_hex') = ?
OR json_extract(payload_json, '$.instructionDiscriminatorHex') = ?
OR json_extract(payload_json, '$.instruction_discriminator_hex') = ?
OR json_extract(payload_json, '$.anchorEventDiscriminatorHex') = ?
OR json_extract(payload_json, '$.anchor_event_discriminator_hex') = ?
OR instr(lower(COALESCE(payload_json, '')), lower(?)) > 0
)
)
"#,
)
.bind(transaction_id)
.bind(protocol_name.to_string())
.bind(audit_event_kind.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.execute(pool)
.await;
if let Err(error) = unlink_result {
return Err(crate::Error::Db(format!(
"cannot unlink replaced instruction audit observation by discriminator on sqlite: {}",
error
)));
}
let delete_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE transaction_id = ?
AND protocol_name = ?
AND event_kind = ?
AND (
json_extract(payload_json, '$.discriminatorHex') = ?
OR json_extract(payload_json, '$.discriminator_hex') = ?
OR json_extract(payload_json, '$.instructionDiscriminatorHex') = ?
OR json_extract(payload_json, '$.instruction_discriminator_hex') = ?
OR json_extract(payload_json, '$.anchorEventDiscriminatorHex') = ?
OR json_extract(payload_json, '$.anchor_event_discriminator_hex') = ?
OR instr(lower(COALESCE(payload_json, '')), lower(?)) > 0
)
"#,
)
.bind(transaction_id)
.bind(protocol_name.to_string())
.bind(audit_event_kind.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.bind(discriminator_hex.to_string())
.execute(pool)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot delete replaced instruction audit by discriminator on sqlite: {}",
error
)));
},
}
},
let delete_result =
crate::query_dex_decoded_events_delete_instruction_audit_by_discriminator(
self.database.as_ref(),
transaction_id,
protocol_name,
audit_event_kind,
discriminator_hex,
)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => return Err(error),
}
}
@@ -797,34 +700,17 @@ WHERE transaction_id = ?
_instruction_id: i64,
anchor_event_discriminator_hex: &str,
) -> Result<(), crate::Error> {
match self.database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let delete_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE transaction_id = ?
AND protocol_name = 'raydium_launchpad'
AND event_kind = 'raydium_launchpad.instruction_audit'
AND json_extract(payload_json, '$.anchorSelfCpiLog') = 1
AND json_extract(payload_json, '$.anchorSelfCpiLogSelectorHex') = ?
AND json_extract(payload_json, '$.anchorEventDiscriminatorHex') = ?
"#,
)
.bind(transaction_id)
.bind(METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX.to_string())
.bind(anchor_event_discriminator_hex.to_string())
.execute(pool)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot delete replaced Raydium Launchpad self-CPI instruction audit on sqlite: {}",
error
)));
},
}
},
let delete_result =
crate::query_dex_decoded_events_delete_raydium_launchpad_anchor_self_cpi_audit(
self.database.as_ref(),
transaction_id,
METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX,
anchor_event_discriminator_hex,
)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => return Err(error),
}
}
@@ -836,50 +722,16 @@ WHERE transaction_id = ?
Some(transaction_id) => transaction_id,
None => return Ok(()),
};
match self.database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let delete_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE id IN (
SELECT audit.id
FROM k_sol_dex_decoded_events audit
WHERE audit.transaction_id = ?
AND audit.protocol_name = 'raydium_launchpad'
AND audit.event_kind = 'raydium_launchpad.instruction_audit'
AND json_extract(audit.payload_json, '$.anchorSelfCpiLog') = 1
AND json_extract(audit.payload_json, '$.anchorSelfCpiLogSelectorHex') = ?
AND EXISTS (
SELECT 1
FROM k_sol_dex_decoded_events direct
WHERE direct.transaction_id = audit.transaction_id
AND direct.protocol_name = 'raydium_launchpad'
AND direct.event_kind IN (
'raydium_launchpad.trade_event',
'raydium_launchpad.pool_create_event',
'raydium_launchpad.claim_vested_event',
'raydium_launchpad.create_vesting_event'
let cleanup_result =
crate::query_dex_decoded_events_cleanup_raydium_launchpad_anchor_self_cpi_audits(
self.database.as_ref(),
transaction_id,
METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX,
)
AND json_extract(direct.payload_json, '$.anchorEventDiscriminatorHex') =
json_extract(audit.payload_json, '$.anchorEventDiscriminatorHex')
)
)
"#,
)
.bind(transaction_id)
.bind(METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX.to_string())
.execute(pool)
.await;
match delete_result {
Ok(_) => return Ok(()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot cleanup replaced Raydium Launchpad self-CPI instruction audits for signature '{}': {}",
transaction.signature, error
)));
},
}
},
.await;
match cleanup_result {
Ok(_) => return Ok(()),
Err(error) => return Err(error),
}
}
@@ -1518,7 +1370,7 @@ WHERE id IN (
event.instruction_id,
"raydium_amm_v4",
event.program_id.clone(),
"raydium_amm_v4.swap",
event.event_kind.as_str(),
Some(event.pool_account.clone()),
None,
Some(event.token_a_mint.clone()),
@@ -1528,6 +1380,24 @@ WHERE id IN (
)
.await;
},
crate::RaydiumAmmV4DecodedEvent::Instruction(event) => {
return self
.materialize_named_dex_event(
transaction,
event.transaction_id,
event.instruction_id,
"raydium_amm_v4",
event.program_id.clone(),
event.event_kind.as_str(),
event.pool_account.clone(),
event.market_account.clone(),
event.token_a_mint.clone(),
event.token_b_mint.clone(),
event.lp_mint.clone(),
event.payload_json.clone(),
)
.await;
},
}
}
@@ -1978,7 +1848,11 @@ WHERE id IN (
let accounts = parse_instruction_accounts_vec(instruction.accounts_json.as_str());
let data_base58 = parse_instruction_data_base58(instruction.data_json.as_deref());
let data_bytes = instruction_data_bytes_from_base58(data_base58.as_deref());
let discriminator_hex = discriminator_hex_from_bytes(data_bytes.as_deref(), 0);
let discriminator_hex = raydium_instruction_discriminator_hex(
audit_spec.protocol_name,
data_bytes.as_deref(),
0,
);
let anchor_event_spec = raydium_launchpad_anchor_self_cpi_event_spec(
audit_spec.protocol_name,
data_bytes.as_deref(),
@@ -2598,6 +2472,17 @@ enum RaydiumMappedNonTradeAmountLayout {
CpmmPoolStatus,
CpmmWithdraw,
LaunchpadInitialize,
AmmV4Initialize,
AmmV4Initialize2,
AmmV4MonitorStep,
AmmV4Deposit,
AmmV4Withdraw,
AmmV4SetParams,
AmmV4WithdrawSrm,
AmmV4PreInitialize,
AmmV4SimulateInfo,
AmmV4AdminCancelOrders,
AmmV4UpdateConfigAccount,
}
fn raydium_instruction_audit_spec(
@@ -2649,6 +2534,9 @@ fn raydium_mapped_non_trade_instruction_spec(
account_count,
);
}
if protocol_name == "raydium_amm_v4" {
return raydium_amm_v4_mapped_non_trade_instruction_spec(discriminator_hex, account_count);
}
if protocol_name == "raydium_clmm" {
if discriminator_hex == "e445a52e51cb9a1d" {
return Some(RaydiumMappedNonTradeInstructionSpec {
@@ -3173,6 +3061,198 @@ fn raydium_mapped_non_trade_instruction_spec(
return None;
}
fn raydium_amm_v4_mapped_non_trade_instruction_spec(
discriminator_hex: &str,
account_count: usize,
) -> std::option::Option<RaydiumMappedNonTradeInstructionSpec> {
match discriminator_hex {
"00" => {
if account_count >= 4 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "initialize",
event_kind: "raydium_amm_v4.initialize",
pool_account_index: Some(3),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4Initialize,
});
}
},
"01" => {
if account_count >= 10 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "initialize2",
event_kind: "raydium_amm_v4.initialize2_pool",
pool_account_index: Some(4),
token_a_mint_index: Some(8),
token_b_mint_index: Some(9),
lp_mint_index: Some(7),
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4Initialize2,
});
}
},
"02" => {
if account_count >= 4 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "monitor_step",
event_kind: "raydium_amm_v4.monitor_step",
pool_account_index: Some(3),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4MonitorStep,
});
}
},
"03" => {
if account_count >= 8 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "deposit",
event_kind: "raydium_amm_v4.deposit",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: Some(5),
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4Deposit,
});
}
},
"04" => {
if account_count >= 8 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "withdraw",
event_kind: "raydium_amm_v4.withdraw",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: Some(5),
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4Withdraw,
});
}
},
"05" => {
if account_count >= 4 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "migrate_to_open_book",
event_kind: "raydium_amm_v4.migrate_to_open_book",
pool_account_index: Some(3),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::None,
});
}
},
"06" => {
if account_count >= 2 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "set_params",
event_kind: "raydium_amm_v4.set_params",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4SetParams,
});
}
},
"07" => {
if account_count >= 2 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "withdraw_pnl",
event_kind: "raydium_amm_v4.withdraw_pnl",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::None,
});
}
},
"08" => {
if account_count >= 2 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "withdraw_srm",
event_kind: "raydium_amm_v4.withdraw_srm",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4WithdrawSrm,
});
}
},
"0a" => {
if account_count >= 5 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "pre_initialize",
event_kind: "raydium_amm_v4.pre_initialize",
pool_account_index: Some(4),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4PreInitialize,
});
}
},
"0c" => {
if account_count >= 2 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "simulate_info",
event_kind: "raydium_amm_v4.simulate_info",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4SimulateInfo,
});
}
},
"0d" => {
if account_count >= 2 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "admin_cancel_orders",
event_kind: "raydium_amm_v4.admin_cancel_orders",
pool_account_index: Some(1),
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4AdminCancelOrders,
});
}
},
"0e" => {
if account_count >= 1 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "create_config_account",
event_kind: "raydium_amm_v4.create_config_account",
pool_account_index: None,
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::None,
});
}
},
"0f" => {
if account_count >= 1 {
return Some(RaydiumMappedNonTradeInstructionSpec {
instruction_name: "update_config_account",
event_kind: "raydium_amm_v4.update_config_account",
pool_account_index: None,
token_a_mint_index: None,
token_b_mint_index: None,
lp_mint_index: None,
amount_layout: RaydiumMappedNonTradeAmountLayout::AmmV4UpdateConfigAccount,
});
}
},
_ => {},
}
return None;
}
fn raydium_launchpad_mapped_non_trade_instruction_spec(
discriminator_hex: &str,
account_count: usize,
@@ -3497,6 +3577,189 @@ fn insert_raydium_mapped_amounts(
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4Initialize => {
if let Some(nonce) = read_u8_from_bytes(data, 1) {
object.insert(
"nonce".to_string(),
serde_json::Value::Number(serde_json::Number::from(nonce as u64)),
);
}
if let Some(open_time) = read_u64_le_from_bytes(data, 2) {
object.insert("openTime".to_string(), serde_json::Value::String(open_time.to_string()));
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4Initialize2 => {
if let Some(nonce) = read_u8_from_bytes(data, 1) {
object.insert(
"nonce".to_string(),
serde_json::Value::Number(serde_json::Number::from(nonce as u64)),
);
}
if let Some(open_time) = read_u64_le_from_bytes(data, 2) {
object.insert("openTime".to_string(), serde_json::Value::String(open_time.to_string()));
}
if let Some(init_pc_amount) = read_u64_le_from_bytes(data, 10) {
object.insert(
"initPcAmount".to_string(),
serde_json::Value::String(init_pc_amount.to_string()),
);
object.insert(
"tokenBAmount".to_string(),
serde_json::Value::String(init_pc_amount.to_string()),
);
}
if let Some(init_coin_amount) = read_u64_le_from_bytes(data, 18) {
object.insert(
"initCoinAmount".to_string(),
serde_json::Value::String(init_coin_amount.to_string()),
);
object.insert(
"tokenAAmount".to_string(),
serde_json::Value::String(init_coin_amount.to_string()),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4MonitorStep => {
if let Some(plan_order_limit) = read_u16_le_from_bytes(data, 1) {
object.insert(
"planOrderLimit".to_string(),
serde_json::Value::Number(serde_json::Number::from(plan_order_limit as u64)),
);
}
if let Some(place_order_limit) = read_u16_le_from_bytes(data, 3) {
object.insert(
"placeOrderLimit".to_string(),
serde_json::Value::Number(serde_json::Number::from(place_order_limit as u64)),
);
}
if let Some(cancel_order_limit) = read_u16_le_from_bytes(data, 5) {
object.insert(
"cancelOrderLimit".to_string(),
serde_json::Value::Number(serde_json::Number::from(cancel_order_limit as u64)),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4Deposit => {
if let Some(max_coin_amount) = read_u64_le_from_bytes(data, 1) {
object.insert(
"maxCoinAmount".to_string(),
serde_json::Value::String(max_coin_amount.to_string()),
);
object.insert(
"tokenAAmount".to_string(),
serde_json::Value::String(max_coin_amount.to_string()),
);
}
if let Some(max_pc_amount) = read_u64_le_from_bytes(data, 9) {
object.insert(
"maxPcAmount".to_string(),
serde_json::Value::String(max_pc_amount.to_string()),
);
object.insert(
"tokenBAmount".to_string(),
serde_json::Value::String(max_pc_amount.to_string()),
);
}
if let Some(base_side) = read_u64_le_from_bytes(data, 17) {
object.insert("baseSide".to_string(), serde_json::Value::String(base_side.to_string()));
}
if let Some(other_amount_min) = read_u64_le_from_bytes(data, 25) {
object.insert(
"otherAmountMin".to_string(),
serde_json::Value::String(other_amount_min.to_string()),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4Withdraw => {
if let Some(lp_amount) = read_u64_le_from_bytes(data, 1) {
object.insert("lpAmountRaw".to_string(), serde_json::Value::String(lp_amount.to_string()));
object.insert("liquidity".to_string(), serde_json::Value::String(lp_amount.to_string()));
}
if let Some(min_coin_amount) = read_u64_le_from_bytes(data, 9) {
object.insert(
"minCoinAmount".to_string(),
serde_json::Value::String(min_coin_amount.to_string()),
);
}
if let Some(min_pc_amount) = read_u64_le_from_bytes(data, 17) {
object.insert(
"minPcAmount".to_string(),
serde_json::Value::String(min_pc_amount.to_string()),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4SetParams => {
if let Some(param) = read_u8_from_bytes(data, 1) {
object.insert(
"configParam".to_string(),
serde_json::Value::Number(serde_json::Number::from(param as u64)),
);
}
if let Some(value) = read_u64_le_from_bytes(data, 2) {
object.insert("configValue".to_string(), serde_json::Value::String(value.to_string()));
}
if let Some(last_order_denominator) = read_u64_le_from_bytes(data, 10) {
object.insert(
"lastOrderDenominator".to_string(),
serde_json::Value::String(last_order_denominator.to_string()),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4WithdrawSrm => {
if let Some(amount) = read_u64_le_from_bytes(data, 1) {
object.insert("amountRaw".to_string(), serde_json::Value::String(amount.to_string()));
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4PreInitialize => {
object.insert("deprecatedInstruction".to_string(), serde_json::Value::Bool(true));
object.insert("partialLifecycle".to_string(), serde_json::Value::Bool(true));
object.insert(
"skipCatalogReason".to_string(),
serde_json::Value::String("missing_token_mints".to_string()),
);
if let Some(nonce) = read_u8_from_bytes(data, 1) {
object.insert(
"nonce".to_string(),
serde_json::Value::Number(serde_json::Number::from(nonce as u64)),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4SimulateInfo => {
if let Some(param) = read_u8_from_bytes(data, 1) {
object.insert(
"simulateParam".to_string(),
serde_json::Value::Number(serde_json::Number::from(param as u64)),
);
}
if let Some(amount_in) = read_u64_le_from_bytes(data, 2) {
object.insert("amountIn".to_string(), serde_json::Value::String(amount_in.to_string()));
}
if let Some(amount_out) = read_u64_le_from_bytes(data, 10) {
object.insert("amountOutOrMinimumAmountOut".to_string(), serde_json::Value::String(amount_out.to_string()));
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4AdminCancelOrders => {
if let Some(limit) = read_u16_le_from_bytes(data, 1) {
object.insert(
"orderCancelLimit".to_string(),
serde_json::Value::Number(serde_json::Number::from(limit as u64)),
);
}
},
RaydiumMappedNonTradeAmountLayout::AmmV4UpdateConfigAccount => {
if let Some(param) = read_u8_from_bytes(data, 1) {
object.insert(
"configParam".to_string(),
serde_json::Value::Number(serde_json::Number::from(param as u64)),
);
}
if let Some(create_pool_fee) = read_u64_le_from_bytes(data, 2) {
object.insert(
"createPoolFee".to_string(),
serde_json::Value::String(create_pool_fee.to_string()),
);
}
},
RaydiumMappedNonTradeAmountLayout::LaunchpadInitialize => {
object.insert(
"poolKindHint".to_string(),
@@ -3555,6 +3818,19 @@ fn read_u8_from_bytes(data: &[u8], offset: usize) -> std::option::Option<u8> {
return Some(data[offset]);
}
fn read_u16_le_from_bytes(data: &[u8], offset: usize) -> std::option::Option<u16> {
if data.len() < offset + 2 {
return None;
}
let mut bytes = [0_u8; 2];
let mut index = 0_usize;
while index < 2 {
bytes[index] = data[offset + index];
index += 1;
}
return Some(u16::from_le_bytes(bytes));
}
fn read_i32_le_from_bytes(data: &[u8], offset: usize) -> std::option::Option<i32> {
if data.len() < offset + 4 {
return None;
@@ -3701,7 +3977,7 @@ fn build_meteora_instruction_audit_payload(
};
let data_base58 = parse_instruction_data_base58(instruction.data_json.as_deref());
let data_bytes = instruction_data_bytes_from_base58(data_base58.as_deref());
let discriminator_hex = discriminator_hex_from_bytes(data_bytes.as_deref(), 0);
let discriminator_hex = raydium_instruction_discriminator_hex(protocol_name, data_bytes.as_deref(), 0);
let anchor_self_cpi_log =
discriminator_hex.as_deref() == Some(METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX);
let anchor_event_discriminator_hex = if anchor_self_cpi_log {
@@ -4239,7 +4515,7 @@ fn build_raydium_instruction_audit_payload(
};
let data_base58 = parse_instruction_data_base58(instruction.data_json.as_deref());
let data_bytes = instruction_data_bytes_from_base58(data_base58.as_deref());
let discriminator_hex = discriminator_hex_from_bytes(data_bytes.as_deref(), 0);
let discriminator_hex = raydium_instruction_discriminator_hex(protocol_name, data_bytes.as_deref(), 0);
let anchor_self_cpi_log =
discriminator_hex.as_deref() == Some(METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX);
let anchor_event_discriminator_hex = if anchor_self_cpi_log {
@@ -4438,6 +4714,40 @@ fn discriminator_hex_from_base58(
return discriminator_hex_from_bytes(bytes.as_deref(), 0);
}
fn raydium_instruction_discriminator_hex(
protocol_name: &str,
bytes: std::option::Option<&[u8]>,
offset: usize,
) -> std::option::Option<std::string::String> {
if protocol_name == "raydium_amm_v4" {
return discriminator_hex_from_bytes_with_len(bytes, offset, 1);
}
return discriminator_hex_from_bytes(bytes, offset);
}
fn discriminator_hex_from_bytes_with_len(
bytes: std::option::Option<&[u8]>,
offset: usize,
length: usize,
) -> std::option::Option<std::string::String> {
let bytes = match bytes {
Some(bytes) => bytes,
None => return None,
};
if bytes.len() < offset + length {
return None;
}
let mut text = std::string::String::new();
let mut index = offset;
let end = offset + length;
while index < end {
let byte = bytes[index];
text.push_str(format!("{byte:02x}").as_str());
index += 1;
}
return Some(text);
}
fn discriminator_hex_from_bytes(
bytes: std::option::Option<&[u8]>,
offset: usize,