0.7.41
This commit is contained in:
@@ -55,6 +55,7 @@ pub use pump_swap::PumpSwapTradeDecoded;
|
||||
pub use raydium_amm_v4::RaydiumAmmV4DecodedEvent;
|
||||
pub use raydium_amm_v4::RaydiumAmmV4Decoder;
|
||||
pub use raydium_amm_v4::RaydiumAmmV4Initialize2PoolDecoded;
|
||||
pub use raydium_amm_v4::RaydiumAmmV4SwapDecoded;
|
||||
pub use raydium_clmm::RaydiumClmmDecodedEvent;
|
||||
pub use raydium_clmm::RaydiumClmmSwapV2Decoded;
|
||||
pub use raydium_clmm::decode_raydium_clmm_instruction;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -562,6 +562,24 @@ impl DexDecodeService {
|
||||
)
|
||||
.await;
|
||||
},
|
||||
crate::RaydiumAmmV4DecodedEvent::Swap(event) => {
|
||||
return self
|
||||
.materialize_named_dex_event(
|
||||
transaction,
|
||||
event.transaction_id,
|
||||
event.instruction_id,
|
||||
"raydium_amm_v4",
|
||||
event.program_id.clone(),
|
||||
"raydium_amm_v4.swap",
|
||||
Some(event.pool_account.clone()),
|
||||
None,
|
||||
Some(event.token_a_mint.clone()),
|
||||
Some(event.token_b_mint.clone()),
|
||||
None,
|
||||
event.payload_json.clone(),
|
||||
)
|
||||
.await;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,9 @@ impl DexDetectService {
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool => {
|
||||
self.detect_raydium_initialize2_pool(&transaction, decoded_event).await
|
||||
},
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Trade => {
|
||||
self.detect_raydium_amm_v4_trade(&transaction, decoded_event).await
|
||||
},
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade => {
|
||||
self.detect_raydium_cpmm_trade(&transaction, decoded_event).await
|
||||
},
|
||||
@@ -522,6 +525,60 @@ impl DexDetectService {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn detect_raydium_amm_v4_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_amm_v4").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_amm_v4",
|
||||
&detection_result,
|
||||
payload_value,
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = signal_result {
|
||||
return Err(error);
|
||||
}
|
||||
return Ok(detection_result);
|
||||
}
|
||||
|
||||
async fn detect_raydium_clmm_trade(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
pub(crate) enum DexDetectionRoute {
|
||||
/// Raydium AMM v4 initialize2 pool route.
|
||||
RaydiumAmmV4Initialize2Pool,
|
||||
/// Raydium AMM v4 trade route.
|
||||
RaydiumAmmV4Trade,
|
||||
/// Raydium CPMM trade route.
|
||||
RaydiumCpmmTrade,
|
||||
/// Raydium CLMM trade route.
|
||||
@@ -45,6 +47,9 @@ pub(crate) fn dex_detection_route(
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool,
|
||||
);
|
||||
},
|
||||
("raydium_amm_v4", "raydium_amm_v4.swap") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Trade);
|
||||
},
|
||||
("raydium_cpmm", "raydium_cpmm.swap_base_input") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade);
|
||||
},
|
||||
|
||||
@@ -235,16 +235,16 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
|
||||
program_id: Some(crate::RAYDIUM_AMM_V4_PROGRAM_ID),
|
||||
router_program_id: None,
|
||||
program_id_status: "known",
|
||||
observed: false,
|
||||
observed: true,
|
||||
decoded: true,
|
||||
materialized: true,
|
||||
trade_candidate: true,
|
||||
candle_candidate: true,
|
||||
pair_candidate: true,
|
||||
pool_candidate: true,
|
||||
status: "partial",
|
||||
confidence: "medium",
|
||||
skip_reason: Some("not_observed_in_0_7_28_replay"),
|
||||
status: "supported",
|
||||
confidence: "high",
|
||||
skip_reason: None,
|
||||
catalog_enabled: true,
|
||||
},
|
||||
DexSupportMatrixEntry {
|
||||
@@ -949,6 +949,22 @@ mod tests {
|
||||
assert_eq!(raydium_entry.code, "raydium_amm_v4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_marks_raydium_amm_v4_supported_after_0_7_41() {
|
||||
let entry = match crate::dex_support_matrix_entry_by_code("raydium_amm_v4") {
|
||||
Some(entry) => entry,
|
||||
None => panic!("expected raydium_amm_v4 matrix entry"),
|
||||
};
|
||||
assert!(entry.observed);
|
||||
assert!(entry.decoded);
|
||||
assert!(entry.materialized);
|
||||
assert!(entry.trade_candidate);
|
||||
assert!(entry.candle_candidate);
|
||||
assert_eq!(entry.status, "supported");
|
||||
assert_eq!(entry.confidence, "high");
|
||||
assert_eq!(entry.skip_reason, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_marks_partial_meteora_damm_v1_correctly() {
|
||||
let entry = match crate::dex_support_matrix_entry_by_code("meteora_damm_v1") {
|
||||
|
||||
@@ -923,6 +923,8 @@ pub use dex::RaydiumAmmV4DecodedEvent;
|
||||
pub use dex::RaydiumAmmV4Decoder;
|
||||
/// Decoded Raydium AmmV4 initialize2 pool event.
|
||||
pub use dex::RaydiumAmmV4Initialize2PoolDecoded;
|
||||
/// Decoded Raydium AMM v4 swap event.
|
||||
pub use dex::RaydiumAmmV4SwapDecoded;
|
||||
/// Decoded Raydium CLMM event.
|
||||
pub use dex::RaydiumClmmDecodedEvent;
|
||||
/// Decoded Raydium CLMM swap_v2 instruction.
|
||||
|
||||
@@ -310,6 +310,20 @@ impl LocalPipelineValidationConfig {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// Builds the `0.7.41` Raydium AMM v4 swap decoder validation config.
|
||||
///
|
||||
/// This profile keeps the Raydium surface diagnostics and labels validation
|
||||
/// runs produced after the AMM v4 swap decoder is active. Missing AMM v4
|
||||
/// remains a warning so empty or unrelated local corpora stay inspectable.
|
||||
pub fn v0_7_41_raydium_amm_v4_swap_decoder() -> Self {
|
||||
let mut config = Self::v0_7_40_raydium_effective_surfaces();
|
||||
config.profile_code = "0.7.41_raydium_amm_v4_swap_decoder".to_string();
|
||||
config.expected_dex_codes = vec!["raydium_amm_v4".to_string()];
|
||||
config.require_all_expected_dexes = false;
|
||||
config.allow_unexpected_dexes = true;
|
||||
return config;
|
||||
}
|
||||
|
||||
/// Builds the legacy `0.7.39` launch-surface validation alias.
|
||||
///
|
||||
/// The implementation now delegates to the DEX-first profile so callers that
|
||||
@@ -551,7 +565,8 @@ impl LocalPipelineValidationService {
|
||||
pub async fn validate_v0_7_39_current_database(
|
||||
&self,
|
||||
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
|
||||
let config = crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
|
||||
let config =
|
||||
crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
|
||||
return self.validate_current_database(&config).await;
|
||||
}
|
||||
|
||||
@@ -562,6 +577,14 @@ impl LocalPipelineValidationService {
|
||||
let config = crate::LocalPipelineValidationConfig::v0_7_40_raydium_effective_surfaces();
|
||||
return self.validate_current_database(&config).await;
|
||||
}
|
||||
|
||||
/// Diagnoses the current database with the `0.7.41` Raydium AMM v4 profile.
|
||||
pub async fn validate_v0_7_41_current_database(
|
||||
&self,
|
||||
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
|
||||
let config = crate::LocalPipelineValidationConfig::v0_7_41_raydium_amm_v4_swap_decoder();
|
||||
return self.validate_current_database(&config).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates a diagnostics summary without performing database access.
|
||||
@@ -687,7 +710,8 @@ pub fn validate_local_pipeline_diagnostics_summary(
|
||||
|| config.profile_code == "0.7.38_token_metadata_gap_prioritization"
|
||||
|| config.profile_code == "0.7.39_dex_first_effective_swap_surfaces"
|
||||
|| config.profile_code == "0.7.39_launch_surface_origin_baseline"
|
||||
|| config.profile_code == "0.7.40_raydium_effective_surfaces";
|
||||
|| config.profile_code == "0.7.40_raydium_effective_surfaces"
|
||||
|| config.profile_code == "0.7.41_raydium_amm_v4_swap_decoder";
|
||||
if config.require_all_expected_dexes || missing_expected_dex_is_warning {
|
||||
for expected_dex_code in &expected_dex_codes {
|
||||
if !observed_dex_codes.contains(expected_dex_code) {
|
||||
@@ -1112,27 +1136,25 @@ mod tests {
|
||||
pair_candle_count: 131,
|
||||
},
|
||||
],
|
||||
raydium_surface_summaries: vec![
|
||||
crate::LocalRaydiumSurfaceDiagnosticSummaryDto {
|
||||
dex_code: "raydium_clmm".to_string(),
|
||||
display_name: "Raydium CLMM".to_string(),
|
||||
surface_role: "dex_effective".to_string(),
|
||||
program_id: Some(crate::RAYDIUM_CLMM_PROGRAM_ID.to_string()),
|
||||
program_id_status: "known".to_string(),
|
||||
status: "supported".to_string(),
|
||||
catalog_enabled: true,
|
||||
instruction_count: 106,
|
||||
transaction_count: 101,
|
||||
decoded_event_count: 106,
|
||||
trade_event_count: 101,
|
||||
pair_candle_count: 131,
|
||||
latest_slot: Some(1),
|
||||
latest_signature: Some("raydium_clmm_fixture".to_string()),
|
||||
observed_in_current_corpus: true,
|
||||
decoded_in_current_corpus: true,
|
||||
trade_materialized_in_current_corpus: true,
|
||||
},
|
||||
],
|
||||
raydium_surface_summaries: vec![crate::LocalRaydiumSurfaceDiagnosticSummaryDto {
|
||||
dex_code: "raydium_clmm".to_string(),
|
||||
display_name: "Raydium CLMM".to_string(),
|
||||
surface_role: "dex_effective".to_string(),
|
||||
program_id: Some(crate::RAYDIUM_CLMM_PROGRAM_ID.to_string()),
|
||||
program_id_status: "known".to_string(),
|
||||
status: "supported".to_string(),
|
||||
catalog_enabled: true,
|
||||
instruction_count: 106,
|
||||
transaction_count: 101,
|
||||
decoded_event_count: 106,
|
||||
trade_event_count: 101,
|
||||
pair_candle_count: 131,
|
||||
latest_slot: Some(1),
|
||||
latest_signature: Some("raydium_clmm_fixture".to_string()),
|
||||
observed_in_current_corpus: true,
|
||||
decoded_in_current_corpus: true,
|
||||
trade_materialized_in_current_corpus: true,
|
||||
}],
|
||||
pair_summaries: vec![],
|
||||
pair_actionability_summaries: vec![
|
||||
crate::LocalPairActionabilityDiagnosticSummaryDto {
|
||||
@@ -1490,7 +1512,8 @@ mod tests {
|
||||
#[test]
|
||||
fn validation_accepts_0_7_39_dex_first_effective_swap_surfaces() {
|
||||
let summary = make_0_7_28_summary_with_meteora();
|
||||
let config = crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
|
||||
let config =
|
||||
crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
|
||||
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
|
||||
assert!(report.validation_passed);
|
||||
assert_eq!(report.validation_profile_code, "0.7.39_dex_first_effective_swap_surfaces");
|
||||
@@ -1509,6 +1532,18 @@ mod tests {
|
||||
assert!(report.expected_dex_codes.contains(&"raydium_amm_v4".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validation_accepts_0_7_41_raydium_amm_v4_swap_decoder_profile() {
|
||||
let summary = make_0_7_28_summary_with_meteora();
|
||||
let config = crate::LocalPipelineValidationConfig::v0_7_41_raydium_amm_v4_swap_decoder();
|
||||
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
|
||||
assert!(report.validation_passed);
|
||||
assert_eq!(report.validation_profile_code, "0.7.41_raydium_amm_v4_swap_decoder");
|
||||
assert_eq!(report.blocking_issue_count, 0);
|
||||
assert!(report.warning_count >= 1);
|
||||
assert!(report.expected_dex_codes.contains(&"raydium_amm_v4".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validation_rejects_0_7_33_pair_trading_readiness_mismatch() {
|
||||
let mut summary = make_0_7_28_summary_with_meteora();
|
||||
|
||||
@@ -96,7 +96,8 @@ pub(crate) async fn resolve_trade_amounts(
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if (input.decoded_event.event_kind.starts_with("raydium_cpmm.")
|
||||
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_clmm."))
|
||||
&& (base_amount_raw.is_none()
|
||||
|| quote_amount_raw.is_none()
|
||||
@@ -114,6 +115,21 @@ pub(crate) async fn resolve_trade_amounts(
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if input.decoded_event.event_kind.starts_with("raydium_amm_v4.")
|
||||
&& (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_cpmm.")
|
||||
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
|
||||
{
|
||||
@@ -204,6 +220,17 @@ pub(crate) async fn resolve_trade_amounts(
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if input.decoded_event.event_kind.starts_with("raydium_amm_v4.") {
|
||||
let vault_side = crate::trade_amount_resolution::infer_trade_side_from_vault_balance_deltas(
|
||||
input.transaction.meta_json.as_deref(),
|
||||
input.transaction.transaction_json.as_str(),
|
||||
input.base_vault_address,
|
||||
input.quote_vault_address,
|
||||
);
|
||||
if vault_side.is_some() {
|
||||
resolved_trade_side = vault_side;
|
||||
}
|
||||
}
|
||||
if input.decoded_event.event_kind.starts_with("meteora_dlmm.") {
|
||||
let vault_side = crate::trade_amount_resolution::infer_trade_side_from_vault_balance_deltas(
|
||||
input.transaction.meta_json.as_deref(),
|
||||
|
||||
Reference in New Issue
Block a user