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

@@ -17,6 +17,7 @@ mod raydium_amm_v4;
mod raydium_clmm;
mod raydium_cpmm;
pub(crate) mod raydium_launchpad;
mod raydium_stable_swap;
pub use dexlab::DexlabCreatePoolDecoded;
pub use dexlab::DexlabDecodedEvent;
@@ -90,3 +91,9 @@ pub use raydium_cpmm::RaydiumCpmmSwapMode;
pub use raydium_cpmm::classify_raydium_cpmm_instruction_data;
pub use raydium_cpmm::decode_raydium_cpmm_instruction;
pub use raydium_cpmm::decode_raydium_cpmm_program_data_event;
pub use raydium_stable_swap::RaydiumStableSwapDecodedEvent;
pub use raydium_stable_swap::RaydiumStableSwapDecoder;
pub use raydium_stable_swap::RaydiumStableSwapInstructionDecoded;
pub use raydium_stable_swap::RaydiumStableSwapSwapEventDecoded;
pub use raydium_stable_swap::classify_raydium_stable_swap_instruction_data;
pub use raydium_stable_swap::decode_raydium_stable_swap_program_data_event;

File diff suppressed because it is too large Load Diff

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);

View File

@@ -108,6 +108,12 @@ impl DexDetectService {
crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade => {
self.detect_raydium_cpmm_trade(&transaction, decoded_event).await
},
crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapTrade => {
self.detect_raydium_stable_swap_trade(&transaction, decoded_event).await
},
crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapPool => {
self.detect_raydium_stable_swap_pool(&transaction, decoded_event).await
},
crate::dex_detection_route::DexDetectionRoute::RaydiumClmmTrade => {
self.detect_raydium_clmm_trade(&transaction, decoded_event).await
},
@@ -668,6 +674,78 @@ impl DexDetectService {
.await;
}
async fn detect_raydium_stable_swap_pool(
&self,
transaction: &crate::ChainTransactionDto,
decoded_event: &crate::DexDecodedEventDto,
) -> Result<crate::DexPoolDetectionResult, crate::Error> {
return self
.detect_materialized_pool_from_decoded_event(
transaction,
decoded_event,
"raydium_stable_swap",
crate::PoolKind::Amm,
crate::PoolStatus::Active,
"signal.dex.raydium_stable_swap",
)
.await;
}
async fn detect_raydium_stable_swap_trade(
&self,
transaction: &crate::ChainTransactionDto,
decoded_event: &crate::DexDecodedEventDto,
) -> Result<crate::DexPoolDetectionResult, crate::Error> {
let dex_id_result =
crate::dex_catalog::ensure_known_dex(self.database.as_ref(), "raydium_stable_swap").await;
let dex_id = match dex_id_result {
Ok(dex_id) => dex_id,
Err(error) => return Err(error),
};
let payload_value_result = parse_payload_json(decoded_event.payload_json.as_str());
let payload_value = match payload_value_result {
Ok(payload_value) => payload_value,
Err(error) => return Err(error),
};
let base_vault_address = extract_payload_string_field(&payload_value, "baseVault");
let quote_vault_address = extract_payload_string_field(&payload_value, "quoteVault");
let input_result =
crate::dex_pool_materialization::DexPoolMaterializationInput::from_decoded_event(
decoded_event,
dex_id,
crate::PoolKind::Amm,
crate::PoolStatus::Active,
crate::dex_pool_materialization::DexPoolTokenOrder::AlreadyBaseQuote,
base_vault_address,
quote_vault_address,
transaction.source_endpoint_name.clone(),
);
let input = match input_result {
Ok(input) => input,
Err(error) => return Err(error),
};
let detection_result =
crate::dex_pool_materialization::materialize_dex_pool(self.database.as_ref(), &input)
.await;
let detection_result = match detection_result {
Ok(detection_result) => detection_result,
Err(error) => return Err(error),
};
let signal_result = self
.record_pool_detection_signals(
transaction,
"signal.dex.raydium_stable_swap",
&detection_result,
payload_value,
)
.await;
if let Err(error) = signal_result {
return Err(error);
}
return Ok(detection_result);
}
async fn detect_raydium_cpmm_trade(
&self,
transaction: &crate::ChainTransactionDto,

View File

@@ -11,6 +11,10 @@ pub(crate) enum DexDetectionRoute {
RaydiumAmmV4Trade,
/// Raydium CPMM trade route.
RaydiumCpmmTrade,
/// Raydium Stable Swap trade route.
RaydiumStableSwapTrade,
/// Raydium Stable Swap pool lifecycle route.
RaydiumStableSwapPool,
/// Raydium CLMM trade route.
RaydiumClmmTrade,
/// Raydium Launchpad pool or bonding-curve creation route.
@@ -67,6 +71,18 @@ pub(crate) fn dex_detection_route(
("raydium_cpmm", "raydium_cpmm.swap_base_output") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade);
},
("raydium_stable_swap", "raydium_stable_swap.initialize") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapPool);
},
("raydium_stable_swap", "raydium_stable_swap.pre_initialize") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapPool);
},
("raydium_stable_swap", "raydium_stable_swap.swap_base_in") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapTrade);
},
("raydium_stable_swap", "raydium_stable_swap.swap_base_out") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapTrade);
},
("raydium_clmm", "raydium_clmm.swap") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumClmmTrade);
},

View File

@@ -260,6 +260,39 @@ fn infer_expected_db_target_for_entry(
);
}
}
if decoder_code == "raydium_stable_swap" {
if entry_name == "initialize" || entry_name == "pre_initialize" {
return Some(
crate::DexEventCoverageEntryDto::DB_TARGET_POOL_LIFECYCLE_EVENTS.to_string(),
);
}
if entry_name == "deposit" || entry_name == "withdraw" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS.to_string());
}
if entry_name == "swap_base_in" || entry_name == "swap_base_out" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_TRADE_EVENTS.to_string());
}
if entry_name == "withdraw_pnl" || entry_name == "withdraw_srm" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_FEE_EVENTS.to_string());
}
if entry_name == "set_params" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_ADMIN_EVENTS.to_string());
}
if entry_name == "monitor_step" || entry_name == "admin_cancel_orders" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_ORDERBOOK_EVENTS.to_string());
}
if entry_name == "update_model_data" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_ADMIN_EVENTS.to_string());
}
if entry_name == "init_model_data"
|| entry_name == "simulate_info"
|| entry_name == "swap_event"
{
return Some(
crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string(),
);
}
}
if decoder_code == "raydium_clmm" {
if entry_name == "initialize_reward" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_REWARD_EVENTS.to_string());
@@ -405,6 +438,9 @@ fn infer_event_family_for_entry(
if decoder_code == "raydium_cpmm" {
return infer_raydium_cpmm_event_family(entry_name, entry_kind);
}
if decoder_code == "raydium_stable_swap" {
return infer_raydium_stable_swap_event_family(entry_name, entry_kind);
}
return infer_event_family(entry_name, entry_kind);
}
@@ -452,6 +488,34 @@ fn infer_raydium_cpmm_event_family(
}
}
fn infer_raydium_stable_swap_event_family(
entry_name: &str,
entry_kind: &str,
) -> std::option::Option<std::string::String> {
if entry_kind == crate::ENTRY_KIND_PROGRAM {
return None;
}
match entry_name {
"initialize" => return Some("pool_create".to_string()),
"pre_initialize" => return Some("pool_create".to_string()),
"init_model_data" => return Some("model_setup".to_string()),
"update_model_data" => return Some("admin_config".to_string()),
"deposit" => return Some("liquidity_add".to_string()),
"withdraw" => return Some("liquidity_remove".to_string()),
"monitor_step" => return Some("order_place".to_string()),
"set_params" => return Some("admin_config".to_string()),
"withdraw_pnl" => return Some("fee".to_string()),
"withdraw_srm" => return Some("fee".to_string()),
"swap_base_in" => return Some("swap".to_string()),
"swap_base_out" => return Some("swap".to_string()),
"simulate_info" => return Some("cpi_transport".to_string()),
"admin_cancel_orders" => return Some("orderbook_admin".to_string()),
"swap_event" => return Some("cpi_transport".to_string()),
_ => return infer_event_family(entry_name, entry_kind),
}
}
fn infer_raydium_clmm_event_family(
entry_name: &str,
entry_kind: &str,
@@ -725,6 +789,32 @@ fn raydium_amm_v4_local_event_kind(entry_name: &str) -> std::option::Option<std:
}
}
fn raydium_stable_swap_local_event_kind(
entry_name: &str,
) -> std::option::Option<std::string::String> {
match entry_name {
"initialize" => return Some("raydium_stable_swap.initialize".to_string()),
"init_model_data" => return Some("raydium_stable_swap.init_model_data".to_string()),
"update_model_data" => return Some("raydium_stable_swap.update_model_data".to_string()),
"pre_initialize" => return Some("raydium_stable_swap.pre_initialize".to_string()),
"deposit" => return Some("raydium_stable_swap.deposit".to_string()),
"withdraw" => return Some("raydium_stable_swap.withdraw".to_string()),
"monitor_step" => return Some("raydium_stable_swap.monitor_step".to_string()),
"set_params" => return Some("raydium_stable_swap.set_params".to_string()),
"withdraw_pnl" => return Some("raydium_stable_swap.withdraw_pnl".to_string()),
"withdraw_srm" => return Some("raydium_stable_swap.withdraw_srm".to_string()),
"swap_base_in" => return Some("raydium_stable_swap.swap_base_in".to_string()),
"swap_base_out" => return Some("raydium_stable_swap.swap_base_out".to_string()),
"simulate_info" => return Some("raydium_stable_swap.simulate_info".to_string()),
"admin_cancel_orders" => {
return Some("raydium_stable_swap.admin_cancel_orders".to_string());
},
"swap_event" => return Some("raydium_stable_swap.swap_event".to_string()),
_ => return None,
}
}
pub(crate) fn known_local_event_kind(
decoder_code: &str,
entry_name: &str,
@@ -732,6 +822,9 @@ pub(crate) fn known_local_event_kind(
if decoder_code == "raydium_amm_v4" {
return raydium_amm_v4_local_event_kind(entry_name);
}
if decoder_code == "raydium_stable_swap" {
return raydium_stable_swap_local_event_kind(entry_name);
}
if decoder_code == "raydium_launchpad" && raydium_launchpad_local_entry_is_known(entry_name) {
return Some(format!("raydium_launchpad.{}", entry_name));
}

View File

@@ -224,7 +224,29 @@ fn resolve_instruction_name(
};
return Some(name.to_string());
}
if program_id == crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID
|| decoder_code == Some("raydium_stable_swap")
{
let name = match discriminator_hex {
"00" => "raydium_stable_swap.initialize",
"01" => "raydium_stable_swap.init_model_data",
"02" => "raydium_stable_swap.update_model_data",
"03" => "raydium_stable_swap.deposit",
"04" => "raydium_stable_swap.withdraw",
"05" => "raydium_stable_swap.monitor_step",
"06" => "raydium_stable_swap.set_params",
"07" => "raydium_stable_swap.withdraw_pnl",
"08" => "raydium_stable_swap.withdraw_srm",
"09" => "raydium_stable_swap.swap_base_in",
"0a" => "raydium_stable_swap.pre_initialize",
"0b" => "raydium_stable_swap.swap_base_out",
"0c" => "raydium_stable_swap.simulate_info",
"0d" => "raydium_stable_swap.admin_cancel_orders",
"40c6cde8260871e2" => "raydium_stable_swap.swap_event",
_ => return None,
};
return Some(name.to_string());
}
if program_id == crate::RAYDIUM_CPMM_PROGRAM_ID || decoder_code == Some("raydium_cpmm") {
let name = match discriminator_hex {
"9c5420764587467b" => "raydium_cpmm.close_permission_pda",
@@ -284,7 +306,6 @@ fn resolve_instruction_name(
};
return Some(name.to_string());
}
if program_id == crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID
|| decoder_code == Some("raydium_launchpad")
{
@@ -309,7 +330,9 @@ fn discriminator_hex_from_data_json(
Some(decoded) => decoded,
None => return None,
};
let discriminator_len = if program_id == crate::RAYDIUM_AMM_V4_PROGRAM_ID {
let discriminator_len = if program_id == crate::RAYDIUM_AMM_V4_PROGRAM_ID
|| program_id == crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID
{
1_usize
} else {
8_usize

View File

@@ -505,6 +505,8 @@ pub use db::FeeEventEntity;
pub use db::InstructionObservationDto;
/// Persisted technical observation for one Solana instruction.
pub use db::InstructionObservationEntity;
/// Raw source row used to rebuild the technical instruction-observation index.
pub use db::InstructionObservationSourceRow;
/// Application-facing known HTTP endpoint DTO.
pub use db::KnownHttpEndpointDto;
/// Application-facing known WebSocket endpoint DTO.
@@ -517,6 +519,8 @@ pub use db::KnownWsEndpointEntity;
pub use db::LaunchAttributionDto;
/// Persisted launch attribution row.
pub use db::LaunchAttributionEntity;
/// Input used to upsert one launch event row.
pub use db::LaunchEventUpsertInput;
/// Application-facing launch surface DTO.
pub use db::LaunchSurfaceDto;
/// Persisted launch surface row.
@@ -762,12 +766,12 @@ pub use db::query_dex_decoded_events_delete_local_replay_scope_by_transaction_id
pub use db::query_dex_decoded_events_delete_locally_covered_upstream_instruction_matches;
/// Deletes Meteora DLMM Anchor self-CPI swap audit rows already covered by decoded swaps.
pub use db::query_dex_decoded_events_delete_meteora_dlmm_anchor_swap_instruction_audits;
/// Deletes decoded DEX instruction audit rows related to one decoded instruction.
pub use db::query_dex_decoded_events_delete_related_instruction_audit;
/// Deletes one Raydium CLMM instruction-audit row by discriminator.
pub use db::query_dex_decoded_events_delete_raydium_clmm_instruction_audit_by_discriminator;
/// Deletes one Raydium Launchpad self-CPI audit row by discriminator.
pub use db::query_dex_decoded_events_delete_raydium_launchpad_anchor_self_cpi_audit;
/// Deletes decoded DEX instruction audit rows related to one decoded instruction.
pub use db::query_dex_decoded_events_delete_related_instruction_audit;
/// Deletes Raydium CLMM instruction-audit rows for locally mapped CLMM instructions.
pub use db::query_dex_decoded_events_delete_replaced_raydium_clmm_instruction_audits;
/// Deletes Raydium CPMM instruction-audit rows already covered by local named rows.
@@ -778,10 +782,10 @@ pub use db::query_dex_decoded_events_get_by_key;
pub use db::query_dex_decoded_events_get_latest_pump_fun_create_payload_by_mint;
/// Lists decoded DEX events for one transaction.
pub use db::query_dex_decoded_events_list_by_transaction_id;
/// Inserts or updates one decoded DEX event row.
pub use db::query_dex_decoded_events_upsert;
/// Updates the persisted payload of one decoded DEX event row.
pub use db::query_dex_decoded_events_update_payload_json_by_id;
/// Inserts or updates one decoded DEX event row.
pub use db::query_dex_decoded_events_upsert;
/// Deletes DEX event coverage entries for one decoder.
pub use db::query_dex_event_coverage_entries_delete_by_decoder;
/// Lists DEX event coverage entries for one decoder.
@@ -819,8 +823,6 @@ pub use db::query_instruction_observations_delete_by_transaction_ids;
pub use db::query_instruction_observations_list_by_filter;
/// Upserts one instruction observation row.
pub use db::query_instruction_observations_upsert;
/// Raw source row used to rebuild the technical instruction-observation index.
pub use db::InstructionObservationSourceRow;
/// Reads one known HTTP endpoint by name.
pub use db::query_known_http_endpoints_get;
/// Lists all known HTTP endpoints.
@@ -841,8 +843,6 @@ pub use db::query_launch_attributions_list_by_pool_id;
pub use db::query_launch_attributions_upsert;
/// Inserts or updates one launch event row.
pub use db::query_launch_events_upsert;
/// Input used to upsert one launch event row.
pub use db::LaunchEventUpsertInput;
/// Returns one launch-surface matching key identified by its kind and value, if it exists.
pub use db::query_launch_surface_keys_get_by_match;
/// Lists all launch-surface matching keys attached to one launch surface id.
@@ -1221,8 +1221,18 @@ pub use dex::RaydiumCpmmSwapDecoded;
pub use dex::RaydiumCpmmSwapEventDecoded;
/// Raydium CPMM swap mode.
pub use dex::RaydiumCpmmSwapMode;
/// Raydium Stable Swap decoded event.
pub use dex::RaydiumStableSwapDecodedEvent;
/// Raydium Stable Swap decoder.
pub use dex::RaydiumStableSwapDecoder;
/// Decoded Raydium Stable Swap instruction.
pub use dex::RaydiumStableSwapInstructionDecoded;
/// Decoded Raydium Stable Swap program-data swap event.
pub use dex::RaydiumStableSwapSwapEventDecoded;
/// Decodes one Raydium CPMM instruction from projected instruction fields.
pub use dex::classify_raydium_cpmm_instruction_data;
/// Classifies one Raydium Stable Swap instruction data payload.
pub use dex::classify_raydium_stable_swap_instruction_data;
/// Decodes a Raydium CLMM instruction.
pub use dex::decode_raydium_clmm_instruction;
/// Decodes one Raydium CLMM Anchor Program data event.
@@ -1231,6 +1241,8 @@ pub use dex::decode_raydium_clmm_program_data_event;
pub use dex::decode_raydium_cpmm_instruction;
/// Decodes Raydium CPMM Anchor events emitted in `Program data:` logs.
pub use dex::decode_raydium_cpmm_program_data_event;
/// Decodes Raydium Stable Swap `Program data:` event payloads.
pub use dex::decode_raydium_stable_swap_program_data_event;
/// DEX decode service.
pub use dex_decode::DexDecodeService;
/// Business-level DEX detection service.

View File

@@ -98,6 +98,7 @@ pub(crate) async fn resolve_trade_amounts(
}
if (input.decoded_event.event_kind.starts_with("raydium_amm_v4.")
|| input.decoded_event.event_kind.starts_with("raydium_cpmm.")
|| input.decoded_event.event_kind.starts_with("raydium_stable_swap.")
|| input.decoded_event.event_kind.starts_with("raydium_clmm."))
&& (base_amount_raw.is_none()
|| quote_amount_raw.is_none()
@@ -183,6 +184,21 @@ pub(crate) async fn resolve_trade_amounts(
return Err(error);
}
}
if input.decoded_event.event_kind.starts_with("raydium_stable_swap.")
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
{
let resolution_result = crate::trade_amount_resolution::apply_vault_balance_delta_fallback(
input,
input.base_vault_address,
input.quote_vault_address,
&mut base_amount_raw,
&mut quote_amount_raw,
&mut price_quote_per_base,
);
if let Err(error) = resolution_result {
return Err(error);
}
}
if input.decoded_event.event_kind.starts_with("raydium_clmm.")
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
{

View File

@@ -12836,6 +12836,28 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/raydium-liquidity-locking-decoder/src/instructions/settle_cp_fee_event.rs",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"init_model_data",
"01",
1,
"docs.raydium.io/products/stable/instructions#initmodeldata-local-corpus-observed",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"update_model_data",
"02",
1,
"docs.raydium.io/products/stable/instructions#updatemodeldata-local-corpus-observed",
),
upstream_git_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
@@ -12869,6 +12891,50 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
1,
"decoders/raydium-stable-swap-decoder/src/instructions/pre_initialize.rs",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"monitor_step",
"05",
1,
"docs.raydium.io/products/stable/instructions#monitorstep-local-corpus-observed",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"set_params",
"06",
1,
"docs.raydium.io/products/stable/instructions#setparams-local-corpus-observed",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"withdraw_pnl",
"07",
1,
"docs.raydium.io/products/stable/instructions#withdrawpnl-local-corpus-observed",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"withdraw_srm",
"08",
1,
"docs.raydium.io/products/stable/instructions#withdrawsrm-local-corpus-observed",
),
upstream_git_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
@@ -12902,6 +12968,39 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
1,
"decoders/raydium-stable-swap-decoder/src/instructions/withdraw.rs",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"simulate_info",
"0c",
1,
"docs.raydium.io/products/stable/instructions#simulateinfo-local-corpus-observed",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_INSTRUCTION,
"admin_cancel_orders",
"0d",
1,
"raydium-amm/program/src/instruction.rs#admincancelorders-stable-local-corpus-observed",
),
manual_solscan_discriminator_entry(
"raydium_stable_swap",
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
"raydium",
"stable_swap",
crate::ENTRY_KIND_EVENT,
"swap_event",
"40c6cde8260871e2",
8,
"docs.raydium.io/products/stable/instructions#program-data-swap-event-decoded-only",
),
upstream_git_discriminator_entry(
"stabble_stable_swap",
Some(crate::STABBLE_STABLE_SWAP_PROGRAM_ID),