0.7.24-pre.2

This commit is contained in:
2026-05-03 07:03:23 +02:00
parent d10a2270d8
commit d44171ca6f
10 changed files with 906 additions and 126 deletions

View File

@@ -203,6 +203,31 @@ impl KbTradeAggregationService {
price_quote_per_base = inferred.2;
}
}
if decoded_event.event_kind.starts_with("pump_fun.")
&& (base_amount_raw.is_none()
|| quote_amount_raw.is_none()
|| price_quote_per_base.is_none())
{
let inferred_result = kb_extract_pump_fun_amounts_from_transaction(
transaction.transaction_json.as_str(),
transaction.meta_json.as_deref(),
base_vault_address.as_deref(),
quote_vault_address.as_deref(),
);
let inferred = match inferred_result {
Ok(inferred) => inferred,
Err(error) => return Err(error),
};
if base_amount_raw.is_none() {
base_amount_raw = inferred.0;
}
if quote_amount_raw.is_none() {
quote_amount_raw = inferred.1;
}
if price_quote_per_base.is_none() {
price_quote_per_base = inferred.2;
}
}
if price_quote_per_base.is_none() {
price_quote_per_base = kb_compute_price_quote_per_base_with_decimals(
transaction.meta_json.as_deref(),
@@ -211,6 +236,12 @@ impl KbTradeAggregationService {
quote_vault_address.as_deref(),
);
}
if price_quote_per_base.is_none() {
price_quote_per_base = kb_compute_price_quote_per_base_from_raw_amounts(
base_amount_raw.as_deref(),
quote_amount_raw.as_deref(),
);
}
let slot_i64 = kb_convert_slot_to_i64(transaction.slot);
let created_trade_event = existing_trade_option.is_none();
let trade_event_dto = crate::KbTradeEventDto::new(
@@ -637,6 +668,146 @@ fn kb_extract_pump_swap_amounts_from_transaction(
Ok((base_amount_raw, quote_amount_raw, price_quote_per_base))
}
fn kb_extract_pump_fun_amounts_from_transaction(
transaction_json: &str,
meta_json: std::option::Option<&str>,
base_vault_address: std::option::Option<&str>,
quote_native_address: std::option::Option<&str>,
) -> Result<
(
std::option::Option<std::string::String>,
std::option::Option<std::string::String>,
std::option::Option<f64>,
),
crate::KbError,
> {
let meta_json = match meta_json {
Some(meta_json) => meta_json,
None => return Ok((None, None, None)),
};
let transaction_value_result = serde_json::from_str::<serde_json::Value>(transaction_json);
let transaction_value = match transaction_value_result {
Ok(transaction_value) => transaction_value,
Err(error) => {
return Err(crate::KbError::Json(format!(
"cannot parse transaction_json for pump_fun amount extraction: {}",
error
)));
}
};
let meta_value_result = serde_json::from_str::<serde_json::Value>(meta_json);
let meta_value = match meta_value_result {
Ok(meta_value) => meta_value,
Err(error) => {
return Err(crate::KbError::Json(format!(
"cannot parse meta_json for pump_fun amount extraction: {}",
error
)));
}
};
let account_keys_result = kb_extract_transaction_account_keys(&transaction_value);
let account_keys = match account_keys_result {
Ok(account_keys) => account_keys,
Err(error) => return Err(error),
};
let pre_balances_result =
kb_extract_token_balance_map(&meta_value, &account_keys, "preTokenBalances");
let pre_balances = match pre_balances_result {
Ok(pre_balances) => pre_balances,
Err(error) => return Err(error),
};
let post_balances_result =
kb_extract_token_balance_map(&meta_value, &account_keys, "postTokenBalances");
let post_balances = match post_balances_result {
Ok(post_balances) => post_balances,
Err(error) => return Err(error),
};
let mut base_amount_raw = None;
let mut quote_amount_raw = None;
let mut price_quote_per_base = None;
let mut base_delta_ui = None;
if let Some(base_vault_address) = base_vault_address {
let base_pre = pre_balances.get(base_vault_address);
let base_post = post_balances.get(base_vault_address);
let base_pre_raw = base_pre.map(|value| value.0.clone());
let base_post_raw = base_post.map(|value| value.0.clone());
base_amount_raw = kb_compute_amount_delta_abs(base_pre_raw, base_post_raw);
let base_pre_ui = base_pre.and_then(|value| value.1);
let base_post_ui = base_post.and_then(|value| value.1);
base_delta_ui = kb_compute_ui_delta_abs(base_pre_ui, base_post_ui);
}
if let Some(quote_native_address) = quote_native_address {
let quote_delta_result = kb_extract_native_balance_delta_by_address(
&meta_value,
&account_keys,
quote_native_address,
);
let quote_delta = match quote_delta_result {
Ok(quote_delta) => quote_delta,
Err(error) => return Err(error),
};
if let Some(quote_delta_lamports) = quote_delta {
quote_amount_raw = Some(quote_delta_lamports.to_string());
let quote_delta_ui = quote_delta_lamports as f64 / 1_000_000_000.0;
if let Some(base_delta_ui) = base_delta_ui {
if base_delta_ui > 0.0 {
price_quote_per_base = Some(quote_delta_ui / base_delta_ui);
}
}
}
}
Ok((base_amount_raw, quote_amount_raw, price_quote_per_base))
}
fn kb_extract_native_balance_delta_by_address(
meta_value: &serde_json::Value,
account_keys: &[std::string::String],
address: &str,
) -> Result<std::option::Option<u64>, crate::KbError> {
let mut account_index = None;
for (index, account_key) in account_keys.iter().enumerate() {
if account_key.as_str() == address {
account_index = Some(index);
break;
}
}
let account_index = match account_index {
Some(account_index) => account_index,
None => return Ok(None),
};
let pre_balances_option = meta_value
.get("preBalances")
.and_then(|value| value.as_array());
let post_balances_option = meta_value
.get("postBalances")
.and_then(|value| value.as_array());
let pre_balances = match pre_balances_option {
Some(pre_balances) => pre_balances,
None => return Ok(None),
};
let post_balances = match post_balances_option {
Some(post_balances) => post_balances,
None => return Ok(None),
};
if account_index >= pre_balances.len() || account_index >= post_balances.len() {
return Ok(None);
}
let pre_balance_option = pre_balances[account_index].as_u64();
let post_balance_option = post_balances[account_index].as_u64();
let pre_balance = match pre_balance_option {
Some(pre_balance) => pre_balance,
None => return Ok(None),
};
let post_balance = match post_balance_option {
Some(post_balance) => post_balance,
None => return Ok(None),
};
if post_balance >= pre_balance {
return Ok(Some(post_balance - pre_balance));
}
Ok(Some(pre_balance - post_balance))
}
fn kb_extract_transaction_account_keys(
transaction_value: &serde_json::Value,
) -> Result<std::vec::Vec<std::string::String>, crate::KbError> {
@@ -792,6 +963,37 @@ fn kb_compute_ui_delta_abs(
Some(delta)
}
fn kb_compute_price_quote_per_base_from_raw_amounts(
base_amount_raw: std::option::Option<&str>,
quote_amount_raw: std::option::Option<&str>,
) -> std::option::Option<f64> {
let base_amount_raw = match base_amount_raw {
Some(base_amount_raw) => base_amount_raw.trim(),
None => return None,
};
let quote_amount_raw = match quote_amount_raw {
Some(quote_amount_raw) => quote_amount_raw.trim(),
None => return None,
};
if base_amount_raw.is_empty() || quote_amount_raw.is_empty() {
return None;
}
let base_amount_result = base_amount_raw.parse::<f64>();
let base_amount = match base_amount_result {
Ok(base_amount) => base_amount,
Err(_) => return None,
};
let quote_amount_result = quote_amount_raw.parse::<f64>();
let quote_amount = match quote_amount_result {
Ok(quote_amount) => quote_amount,
Err(_) => return None,
};
if base_amount <= 0.0 {
return None;
}
Some(quote_amount / base_amount)
}
fn kb_compute_price_quote_per_base_with_decimals(
meta_json: std::option::Option<&str>,
transaction_json: &str,