This commit is contained in:
2026-06-11 17:22:55 +02:00
parent bfdb2e69ae
commit 38f42da970
23 changed files with 2650 additions and 35 deletions

View File

@@ -11,6 +11,7 @@ pub struct DexDecodeService {
persistence: crate::DetectionPersistenceService,
raydium_amm_v4_decoder: crate::RaydiumAmmV4Decoder,
raydium_clmm_decoder: crate::RaydiumClmmDecoder,
raydium_stable_swap_decoder: crate::RaydiumStableSwapDecoder,
pump_fun_decoder: crate::PumpFunDecoder,
pump_swap_decoder: crate::PumpSwapDecoder,
orca_whirlpools_decoder: crate::OrcaWhirlpoolsDecoder,
@@ -33,6 +34,7 @@ impl DexDecodeService {
persistence,
raydium_amm_v4_decoder: crate::RaydiumAmmV4Decoder::new(),
raydium_clmm_decoder: crate::RaydiumClmmDecoder::new(),
raydium_stable_swap_decoder: crate::RaydiumStableSwapDecoder::new(),
pump_fun_decoder: crate::PumpFunDecoder::new(),
pump_swap_decoder: crate::PumpSwapDecoder::new(),
orca_whirlpools_decoder: crate::OrcaWhirlpoolsDecoder::new(),
@@ -78,6 +80,13 @@ impl DexDecodeService {
if let Err(error) = append_result {
return Err(error);
}
let append_result = append_persisted_events_result(
&mut persisted,
self.decode_and_persist_raydium_stable_swap_events(&transaction, &instructions).await,
);
if let Err(error) = append_result {
return Err(error);
}
let append_result = append_persisted_events_result(
&mut persisted,
self.decode_and_persist_raydium_clmm_events(&transaction, &instructions).await,
@@ -1512,6 +1521,65 @@ impl DexDecodeService {
.await;
}
async fn persist_raydium_stable_swap_event(
&self,
transaction: &crate::ChainTransactionDto,
decoded_event: &crate::RaydiumStableSwapDecodedEvent,
) -> Result<crate::DexDecodedEventDto, crate::Error> {
let transaction_id = match transaction.id {
Some(transaction_id) => transaction_id,
None => {
return Err(crate::Error::InvalidState(format!(
"transaction '{}' has no internal id",
transaction.signature
)));
},
};
let instruction_id = match decoded_event.instruction_id() {
Some(instruction_id) => instruction_id,
None => {
return Err(crate::Error::InvalidState(format!(
"raydium stable swap decoded event for transaction '{}' has no instruction id",
transaction.signature
)));
},
};
let event_kind = decoded_event.event_kind().to_string();
let raw_payload_json = match decoded_event.to_payload_json() {
Some(payload_json) => payload_json,
None => {
return Err(crate::Error::Json(
"cannot serialize decoded raydium stable swap payload".to_string(),
));
},
};
let payload_value_result = enriched_raydium_payload_value(
"raydium_stable_swap",
event_kind.as_str(),
raw_payload_json.as_str(),
);
let payload_value = match payload_value_result {
Ok(payload_value) => payload_value,
Err(error) => return Err(error),
};
return self
.materialize_named_dex_event(
transaction,
transaction_id,
instruction_id,
"raydium_stable_swap",
crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID.to_string(),
event_kind.as_str(),
decoded_event.pool_account().map(|value| return value.to_string()),
decoded_event.market_account().map(|value| return value.to_string()),
decoded_event.base_mint().map(|value| return value.to_string()),
decoded_event.quote_mint().map(|value| return value.to_string()),
decoded_event.lp_mint().map(|value| return value.to_string()),
payload_value,
)
.await;
}
async fn persist_pump_fun_event(
&self,
transaction: &crate::ChainTransactionDto,
@@ -1708,6 +1776,32 @@ impl DexDecodeService {
return Ok(persisted);
}
async fn decode_and_persist_raydium_stable_swap_events(
&self,
transaction: &crate::ChainTransactionDto,
instructions: &[crate::ChainInstructionDto],
) -> Result<std::vec::Vec<crate::DexDecodedEventDto>, crate::Error> {
let decoded_result = self
.raydium_stable_swap_decoder
.decode_transaction(transaction, instructions);
let decoded_events = match decoded_result {
Ok(decoded_events) => decoded_events,
Err(error) => return Err(error),
};
let mut persisted = std::vec::Vec::new();
for decoded_event in &decoded_events {
let persist_result = self
.persist_raydium_stable_swap_event(transaction, decoded_event)
.await;
let persisted_event = match persist_result {
Ok(persisted_event) => persisted_event,
Err(error) => return Err(error),
};
persisted.push(persisted_event);
}
return Ok(persisted);
}
async fn decode_and_persist_raydium_clmm_events(
&self,
transaction: &crate::ChainTransactionDto,
@@ -2509,6 +2603,13 @@ fn raydium_instruction_audit_spec(
candidate_pool_account_index: 3,
});
}
if program_id == crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID {
return Some(RaydiumInstructionAuditSpec {
protocol_name: "raydium_stable_swap",
event_kind: "raydium_stable_swap.instruction_audit",
candidate_pool_account_index: 1,
});
}
if program_id == crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID {
return Some(RaydiumInstructionAuditSpec {
protocol_name: "raydium_launchpad",
@@ -4234,6 +4335,7 @@ fn instruction_audit_event_kind_by_protocol(
"raydium_amm_v4" => return Some("raydium_amm_v4.instruction_audit"),
"raydium_clmm" => return Some("raydium_clmm.instruction_audit"),
"raydium_cpmm" => return Some("raydium_cpmm.instruction_audit"),
"raydium_stable_swap" => return Some("raydium_stable_swap.instruction_audit"),
"raydium_launchpad" => return Some("raydium_launchpad.instruction_audit"),
"meteora_dlmm" => return Some("meteora_dlmm.instruction_audit"),
"meteora_damm_v1" => return Some("meteora_damm_v1.instruction_audit"),
@@ -4719,7 +4821,7 @@ fn raydium_instruction_discriminator_hex(
bytes: std::option::Option<&[u8]>,
offset: usize,
) -> std::option::Option<std::string::String> {
if protocol_name == "raydium_amm_v4" {
if protocol_name == "raydium_amm_v4" || protocol_name == "raydium_stable_swap" {
return discriminator_hex_from_bytes_with_len(bytes, offset, 1);
}
return discriminator_hex_from_bytes(bytes, offset);