0.7.28 - final

This commit is contained in:
2026-05-12 15:04:04 +02:00
parent 7f130dba6b
commit 4f6a4806e2
34 changed files with 4020 additions and 199 deletions

View File

@@ -195,6 +195,37 @@ pub fn is_dex_admin_event_kind(event_kind: &str) -> bool {
return false;
}
/// Returns true when a decoded payload contains at least one direct amount or price field.
///
/// This is a conservative payload-level check. It does not inspect transaction
/// token balance deltas and is intended for protocol decoders that cannot yet
/// produce a deterministic materializable swap payload.
pub(crate) fn decoded_payload_has_trade_amount_or_price_payload(
payload: &serde_json::Value,
) -> bool {
return value_contains_any_non_null_key(
payload,
&[
"baseAmountRaw",
"base_amount_raw",
"baseAmount",
"amountBase",
"amountInBase",
"quoteAmountRaw",
"quote_amount_raw",
"quoteAmount",
"amountQuote",
"amountOutQuote",
"amountIn",
"amountOut",
"priceQuotePerBase",
"price_quote_per_base",
"quotePerBase",
"lastPriceQuotePerBase",
],
);
}
/// Returns true when a decoded payload is marked as a trade candidate.
///
/// Explicit payload metadata wins over event-kind inference. This allows
@@ -332,6 +363,38 @@ fn json_insert_i64_if_missing(
object.insert(key.to_owned(), serde_json::Value::Number(serde_json::Number::from(value)));
}
fn value_contains_any_non_null_key(value: &serde_json::Value, candidate_keys: &[&str]) -> bool {
if let Some(object) = value.as_object() {
for candidate_key in candidate_keys {
let candidate_value_option = object.get(*candidate_key);
if let Some(candidate_value) = candidate_value_option {
if !candidate_value.is_null() {
if let Some(text) = candidate_value.as_str() {
if text.trim().is_empty() {
continue;
}
}
return true;
}
}
}
for nested_value in object.values() {
if value_contains_any_non_null_key(nested_value, candidate_keys) {
return true;
}
}
return false;
}
if let Some(array) = value.as_array() {
for nested_value in array {
if value_contains_any_non_null_key(nested_value, candidate_keys) {
return true;
}
}
}
return false;
}
fn extract_top_level_bool_by_candidate_keys(
payload: &serde_json::Value,
candidate_keys: &[&str],
@@ -506,4 +569,20 @@ mod tests {
assert!(!super::is_decoded_event_trade_candidate("pump_swap.buy", &payload_json));
assert!(!super::is_decoded_event_candle_candidate("pump_swap.buy", &payload_json));
}
#[test]
fn detects_direct_amount_or_price_payload_recursively() {
let payload_json = serde_json::json!({
"nested": {
"quoteAmountRaw": "2500"
}
});
assert!(super::decoded_payload_has_trade_amount_or_price_payload(&payload_json));
let empty_payload_json = serde_json::json!({
"nested": {
"quoteAmountRaw": ""
}
});
assert!(!super::decoded_payload_has_trade_amount_or_price_payload(&empty_payload_json));
}
}