pool/swap better detection
This commit is contained in:
@@ -62,6 +62,13 @@ pub enum KbMeteoraDbcDecodedEvent {
|
|||||||
Swap(KbMeteoraDbcSwapDecoded),
|
Swap(KbMeteoraDbcSwapDecoded),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum KbMeteoraDbcInstructionKind {
|
||||||
|
CreatePool,
|
||||||
|
Swap,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
/// Meteora DBC decoder.
|
/// Meteora DBC decoder.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct KbMeteoraDbcDecoder;
|
pub struct KbMeteoraDbcDecoder;
|
||||||
@@ -129,25 +136,8 @@ impl KbMeteoraDbcDecoder {
|
|||||||
Ok(parsed_json) => parsed_json,
|
Ok(parsed_json) => parsed_json,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
let is_create_pool = kb_log_messages_contain_any_keyword(
|
let instruction_kind =
|
||||||
&log_messages,
|
kb_classify_instruction_kind(parsed_json.as_ref(), &log_messages);
|
||||||
&[
|
|
||||||
"create_pool",
|
|
||||||
"createpool",
|
|
||||||
"initialize_pool",
|
|
||||||
"initializepool",
|
|
||||||
"launch_pool",
|
|
||||||
],
|
|
||||||
) || kb_value_contains_any_key(
|
|
||||||
parsed_json.as_ref(),
|
|
||||||
&[
|
|
||||||
"poolConfig",
|
|
||||||
"migrationQuoteThreshold",
|
|
||||||
"curveConfig",
|
|
||||||
"dbcConfig",
|
|
||||||
],
|
|
||||||
);
|
|
||||||
let is_swap = kb_log_messages_contain_any_keyword(&log_messages, &["swap2", "swap"]);
|
|
||||||
let pool_account = kb_extract_string_by_candidate_keys(
|
let pool_account = kb_extract_string_by_candidate_keys(
|
||||||
parsed_json.as_ref(),
|
parsed_json.as_ref(),
|
||||||
&["pool", "poolAccount", "poolState", "virtualPool", "poolKey"],
|
&["pool", "poolAccount", "poolState", "virtualPool", "poolKey"],
|
||||||
@@ -173,10 +163,11 @@ impl KbMeteoraDbcDecoder {
|
|||||||
&["creator", "poolCreator", "owner", "user"],
|
&["creator", "poolCreator", "owner", "user"],
|
||||||
)
|
)
|
||||||
.or_else(|| kb_extract_account(&accounts, 4));
|
.or_else(|| kb_extract_account(&accounts, 4));
|
||||||
if is_create_pool {
|
if instruction_kind == KbMeteoraDbcInstructionKind::CreatePool {
|
||||||
let payload_json = serde_json::json!({
|
let payload_json = serde_json::json!({
|
||||||
"decoder": "meteora_dbc",
|
"decoder": "meteora_dbc",
|
||||||
"eventKind": "create_pool",
|
"eventKind": "create_pool",
|
||||||
|
"classifiedInstructionKind": "create_pool",
|
||||||
"signature": transaction.signature,
|
"signature": transaction.signature,
|
||||||
"instructionId": instruction_id,
|
"instructionId": instruction_id,
|
||||||
"instructionIndex": instruction.instruction_index,
|
"instructionIndex": instruction.instruction_index,
|
||||||
@@ -205,11 +196,12 @@ impl KbMeteoraDbcDecoder {
|
|||||||
));
|
));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if is_swap {
|
if instruction_kind == KbMeteoraDbcInstructionKind::Swap {
|
||||||
let trade_side = kb_infer_trade_side(&log_messages);
|
let trade_side = kb_infer_trade_side(&log_messages);
|
||||||
let payload_json = serde_json::json!({
|
let payload_json = serde_json::json!({
|
||||||
"decoder": "meteora_dbc",
|
"decoder": "meteora_dbc",
|
||||||
"eventKind": "swap",
|
"eventKind": "swap",
|
||||||
|
"classifiedInstructionKind": "swap",
|
||||||
"signature": transaction.signature,
|
"signature": transaction.signature,
|
||||||
"instructionId": instruction_id,
|
"instructionId": instruction_id,
|
||||||
"instructionIndex": instruction.instruction_index,
|
"instructionIndex": instruction.instruction_index,
|
||||||
@@ -442,6 +434,56 @@ fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTra
|
|||||||
crate::KbSwapTradeSide::Unknown
|
crate::KbSwapTradeSide::Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn kb_classify_instruction_kind(
|
||||||
|
parsed_json: std::option::Option<&serde_json::Value>,
|
||||||
|
log_messages: &[std::string::String],
|
||||||
|
) -> KbMeteoraDbcInstructionKind {
|
||||||
|
let parsed_instruction_name = kb_extract_string_by_candidate_keys(
|
||||||
|
parsed_json,
|
||||||
|
&["instruction", "instructionName", "type", "name"],
|
||||||
|
);
|
||||||
|
if let Some(parsed_instruction_name) = parsed_instruction_name {
|
||||||
|
let normalized = kb_normalize_log_text(parsed_instruction_name.as_str());
|
||||||
|
if normalized.contains("createpool")
|
||||||
|
|| normalized.contains("initializepool")
|
||||||
|
|| normalized.contains("launchpool")
|
||||||
|
{
|
||||||
|
return KbMeteoraDbcInstructionKind::CreatePool;
|
||||||
|
}
|
||||||
|
if normalized == "swap" || normalized == "swap2" {
|
||||||
|
return KbMeteoraDbcInstructionKind::Swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let has_create_config = kb_value_contains_any_key(
|
||||||
|
parsed_json,
|
||||||
|
&[
|
||||||
|
"poolConfig",
|
||||||
|
"migrationQuoteThreshold",
|
||||||
|
"curveConfig",
|
||||||
|
"dbcConfig",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
if has_create_config {
|
||||||
|
return KbMeteoraDbcInstructionKind::CreatePool;
|
||||||
|
}
|
||||||
|
if kb_log_messages_contain_any_keyword(
|
||||||
|
log_messages,
|
||||||
|
&[
|
||||||
|
"create_pool",
|
||||||
|
"createpool",
|
||||||
|
"initialize_pool",
|
||||||
|
"initializepool",
|
||||||
|
"launch_pool",
|
||||||
|
],
|
||||||
|
) {
|
||||||
|
return KbMeteoraDbcInstructionKind::CreatePool;
|
||||||
|
}
|
||||||
|
if kb_log_messages_contain_any_keyword(log_messages, &["swap2", "swap"]) {
|
||||||
|
return KbMeteoraDbcInstructionKind::Swap;
|
||||||
|
}
|
||||||
|
KbMeteoraDbcInstructionKind::Unknown
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn make_create_transaction() -> crate::KbChainTransactionDto {
|
fn make_create_transaction() -> crate::KbChainTransactionDto {
|
||||||
@@ -624,4 +666,50 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn meteora_dbc_quote_mint_alone_does_not_trigger_create_pool() {
|
||||||
|
let decoder = crate::KbMeteoraDbcDecoder::new();
|
||||||
|
let transaction = make_swap_transaction();
|
||||||
|
let mut instruction = make_swap_instruction();
|
||||||
|
instruction.parsed_json = Some(
|
||||||
|
serde_json::json!({
|
||||||
|
"info": {
|
||||||
|
"quoteMint": "So11111111111111111111111111111111111111112"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
let decoded_result = decoder.decode_transaction(&transaction, &[instruction]);
|
||||||
|
let decoded = match decoded_result {
|
||||||
|
Ok(decoded) => decoded,
|
||||||
|
Err(error) => panic!("decode must succeed: {}", error),
|
||||||
|
};
|
||||||
|
assert_eq!(decoded.len(), 1);
|
||||||
|
match &decoded[0] {
|
||||||
|
crate::KbMeteoraDbcDecodedEvent::Swap(_) => {}
|
||||||
|
crate::KbMeteoraDbcDecodedEvent::CreatePool(_) => {
|
||||||
|
panic!("unexpected create event")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn meteora_dbc_pool_config_triggers_create_pool() {
|
||||||
|
let decoder = crate::KbMeteoraDbcDecoder::new();
|
||||||
|
let transaction = make_create_transaction();
|
||||||
|
let instruction = make_create_instruction();
|
||||||
|
let decoded_result = decoder.decode_transaction(&transaction, &[instruction]);
|
||||||
|
let decoded = match decoded_result {
|
||||||
|
Ok(decoded) => decoded,
|
||||||
|
Err(error) => panic!("decode must succeed: {}", error),
|
||||||
|
};
|
||||||
|
assert_eq!(decoded.len(), 1);
|
||||||
|
match &decoded[0] {
|
||||||
|
crate::KbMeteoraDbcDecodedEvent::CreatePool(_) => {}
|
||||||
|
crate::KbMeteoraDbcDecodedEvent::Swap(_) => {
|
||||||
|
panic!("unexpected swap event")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user