This commit is contained in:
2026-05-29 07:38:24 +02:00
parent 96b6209482
commit ffa4acbccb
15 changed files with 1982 additions and 107 deletions

View File

@@ -128,6 +128,109 @@ WHERE transaction_id = ?
}
}
/// Deletes decoded DEX instruction audit rows related to one decoded instruction.
///
/// This removes an audit row attached to the decoded instruction itself, its direct
/// parent instruction, or its direct child instructions inside the same transaction.
pub async fn query_dex_decoded_events_delete_related_instruction_audit(
database: &crate::Database,
transaction_id: i64,
instruction_id: i64,
audit_event_kind: &str,
) -> Result<u64, crate::Error> {
match database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let query_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE transaction_id = ?
AND event_kind = ?
AND instruction_id IN (
SELECT id
FROM k_sol_chain_instructions
WHERE transaction_id = ?
AND id = ?
UNION
SELECT parent_instruction_id
FROM k_sol_chain_instructions
WHERE transaction_id = ?
AND id = ?
AND parent_instruction_id IS NOT NULL
UNION
SELECT id
FROM k_sol_chain_instructions
WHERE transaction_id = ?
AND parent_instruction_id = ?
)
"#,
)
.bind(transaction_id)
.bind(audit_event_kind)
.bind(transaction_id)
.bind(instruction_id)
.bind(transaction_id)
.bind(instruction_id)
.bind(transaction_id)
.bind(instruction_id)
.execute(pool)
.await;
match query_result {
Ok(result) => return Ok(result.rows_affected()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot delete related instruction audit events on sqlite: {}",
error
)));
},
}
},
}
}
/// Deletes Meteora DLMM Anchor self-CPI swap audit rows already covered by decoded swaps.
///
/// This targets only local-corpus-observed Anchor event discriminators that are
/// decoded into `meteora_dlmm.swap` payload enrichment. It does not delete
/// unrelated DLMM instruction audits.
pub async fn query_dex_decoded_events_delete_meteora_dlmm_anchor_swap_instruction_audits(
database: &crate::Database,
transaction_id: i64,
) -> Result<u64, crate::Error> {
match database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let query_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE transaction_id = ?
AND protocol_name = 'meteora_dlmm'
AND event_kind = 'meteora_dlmm.instruction_audit'
AND json_extract(payload_json, '$.anchorSelfCpiLog') = 1
AND json_extract(payload_json, '$.anchorEventDiscriminatorHex') IN (
'516ce3becdd00ac4',
'2e7452d7941b544d'
)
"#,
)
.bind(transaction_id)
.execute(pool)
.await;
match query_result {
Ok(result) => return Ok(result.rows_affected()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot delete Meteora DLMM Anchor swap audit events on sqlite: {}",
error
)));
},
}
},
}
}
/// Reads one decoded DEX event by its natural key.
pub async fn query_dex_decoded_events_get_by_key(
database: &crate::Database,
@@ -400,4 +503,106 @@ mod tests {
assert_eq!(listed.len(), 1);
assert_eq!(listed[0].event_kind, "raydium_amm_v4.initialize2_pool");
}
#[tokio::test]
async fn related_instruction_audit_delete_removes_parent_audit_for_child_decode() {
let database = make_database().await;
let transaction_dto = crate::ChainTransactionDto::new(
"sig-dex-event-related-audit-test-1".to_string(),
None,
None,
Some("helius_primary_http".to_string()),
Some("0".to_string()),
None,
None,
r#"{"transaction":{"message":{"instructions":[]}}}"#.to_string(),
);
let transaction_id_result =
crate::query_chain_transactions_upsert(&database, &transaction_dto).await;
let transaction_id = match transaction_id_result {
Ok(transaction_id) => transaction_id,
Err(error) => panic!("transaction upsert must succeed: {}", error),
};
let parent_instruction_dto = crate::ChainInstructionDto::new(
transaction_id,
None,
0,
None,
Some(crate::METEORA_DLMM_PROGRAM_ID.to_string()),
Some("meteora-dlmm".to_string()),
Some(1),
r#"["ParentAccount","Pool111"]"#.to_string(),
None,
None,
None,
);
let parent_instruction_id_result =
crate::query_chain_instructions_insert(&database, &parent_instruction_dto).await;
let parent_instruction_id = match parent_instruction_id_result {
Ok(parent_instruction_id) => parent_instruction_id,
Err(error) => panic!("parent instruction insert must succeed: {}", error),
};
let child_instruction_dto = crate::ChainInstructionDto::new(
transaction_id,
Some(parent_instruction_id),
0,
Some(0),
Some(crate::METEORA_DLMM_PROGRAM_ID.to_string()),
Some("meteora-dlmm".to_string()),
Some(2),
r#"["ChildAccount","Pool111"]"#.to_string(),
None,
None,
None,
);
let child_instruction_id_result =
crate::query_chain_instructions_insert(&database, &child_instruction_dto).await;
let child_instruction_id = match child_instruction_id_result {
Ok(child_instruction_id) => child_instruction_id,
Err(error) => panic!("child instruction insert must succeed: {}", error),
};
let audit_dto = crate::DexDecodedEventDto::new(
transaction_id,
Some(parent_instruction_id),
"meteora_dlmm".to_string(),
crate::METEORA_DLMM_PROGRAM_ID.to_string(),
"meteora_dlmm.instruction_audit".to_string(),
Some("Pool111".to_string()),
None,
None,
None,
None,
r#"{"audit":true}"#.to_string(),
);
let audit_upsert_result =
crate::query_dex_decoded_events_upsert(&database, &audit_dto).await;
match audit_upsert_result {
Ok(_) => {},
Err(error) => panic!("audit upsert must succeed: {}", error),
}
let deleted_result = super::query_dex_decoded_events_delete_related_instruction_audit(
&database,
transaction_id,
child_instruction_id,
"meteora_dlmm.instruction_audit",
)
.await;
let deleted = match deleted_result {
Ok(deleted) => deleted,
Err(error) => panic!("related audit delete must succeed: {}", error),
};
assert_eq!(deleted, 1);
let fetched_result = crate::query_dex_decoded_events_get_by_key(
&database,
transaction_id,
Some(parent_instruction_id),
"meteora_dlmm.instruction_audit",
)
.await;
let fetched = match fetched_result {
Ok(fetched) => fetched,
Err(error) => panic!("audit fetch must succeed: {}", error),
};
assert!(fetched.is_none());
}
}