0.5.2
This commit is contained in:
@@ -8,7 +8,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobot"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobot"
|
||||||
|
|||||||
@@ -88,51 +88,54 @@ pub(crate) fn classify_domain_event(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if detected_programs.is_empty() {
|
if detected_programs.is_empty() {
|
||||||
return Ok(Some(
|
return Ok(Some(KhbbClassifiedDomainEvent::UnknownProgramLogActivity(
|
||||||
KhbbClassifiedDomainEvent::UnknownProgramLogActivity(
|
KhbbUnknownProgramLogActivityEvent {
|
||||||
KhbbUnknownProgramLogActivityEvent {
|
|
||||||
signature: log_event.signature.clone(),
|
|
||||||
context_slot: log_event.context_slot,
|
|
||||||
has_error: log_event.has_error,
|
|
||||||
log_count: log_event.log_count,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(Some(
|
|
||||||
KhbbClassifiedDomainEvent::KnownProgramLogActivity(
|
|
||||||
KhbbKnownProgramLogActivityEvent {
|
|
||||||
signature: log_event.signature.clone(),
|
signature: log_event.signature.clone(),
|
||||||
context_slot: log_event.context_slot,
|
context_slot: log_event.context_slot,
|
||||||
has_error: log_event.has_error,
|
has_error: log_event.has_error,
|
||||||
programs: detected_programs,
|
log_count: log_event.log_count,
|
||||||
},
|
},
|
||||||
),
|
)));
|
||||||
))
|
}
|
||||||
}
|
Ok(Some(KhbbClassifiedDomainEvent::KnownProgramLogActivity(
|
||||||
|
KhbbKnownProgramLogActivityEvent {
|
||||||
|
signature: log_event.signature.clone(),
|
||||||
|
context_slot: log_event.context_slot,
|
||||||
|
has_error: log_event.has_error,
|
||||||
|
programs: detected_programs,
|
||||||
|
},
|
||||||
|
)))
|
||||||
|
},
|
||||||
crate::KhbbDomainEvent::TokenProgramActivity(token_event) => {
|
crate::KhbbDomainEvent::TokenProgramActivity(token_event) => {
|
||||||
match token_event.token_program_family.as_str() {
|
let source_label = match token_event.source_label.as_deref() {
|
||||||
"spl-token" => Ok(Some(
|
Some(value) => value,
|
||||||
KhbbClassifiedDomainEvent::SplTokenProgramActivity(
|
None => {
|
||||||
|
return Ok(None);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let known_program = crate::program_registry::classify_known_program_id(source_label);
|
||||||
|
match known_program {
|
||||||
|
Some(crate::program_registry::KhbbKnownProgram::SplToken) => {
|
||||||
|
Ok(Some(KhbbClassifiedDomainEvent::SplTokenProgramActivity(
|
||||||
KhbbSplTokenProgramActivityEvent {
|
KhbbSplTokenProgramActivityEvent {
|
||||||
pubkey: token_event.pubkey.clone(),
|
pubkey: token_event.pubkey.clone(),
|
||||||
context_slot: token_event.context_slot,
|
context_slot: token_event.context_slot,
|
||||||
subscription_id: token_event.subscription_id,
|
subscription_id: token_event.subscription_id,
|
||||||
},
|
},
|
||||||
),
|
)))
|
||||||
)),
|
},
|
||||||
"spl-token-2022" => Ok(Some(
|
Some(crate::program_registry::KhbbKnownProgram::SplToken2022) => {
|
||||||
KhbbClassifiedDomainEvent::SplToken2022ProgramActivity(
|
Ok(Some(KhbbClassifiedDomainEvent::SplToken2022ProgramActivity(
|
||||||
KhbbSplToken2022ProgramActivityEvent {
|
KhbbSplToken2022ProgramActivityEvent {
|
||||||
pubkey: token_event.pubkey.clone(),
|
pubkey: token_event.pubkey.clone(),
|
||||||
context_slot: token_event.context_slot,
|
context_slot: token_event.context_slot,
|
||||||
subscription_id: token_event.subscription_id,
|
subscription_id: token_event.subscription_id,
|
||||||
},
|
},
|
||||||
),
|
)))
|
||||||
)),
|
},
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,8 +143,8 @@ pub(crate) fn classify_domain_event(
|
|||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn classify_token_program_activity_as_spl_token() {
|
fn classify_token_program_activity_as_spl_token() {
|
||||||
let event = crate::KhbbDomainEvent::TokenProgramActivity(
|
let event =
|
||||||
crate::KhbbTokenProgramActivityEvent {
|
crate::KhbbDomainEvent::TokenProgramActivity(crate::KhbbTokenProgramActivityEvent {
|
||||||
subscription_id: 1,
|
subscription_id: 1,
|
||||||
source_kind: crate::KhbbWsSubscriptionKind::Program,
|
source_kind: crate::KhbbWsSubscriptionKind::Program,
|
||||||
source_label: Some(std::string::String::from(
|
source_label: Some(std::string::String::from(
|
||||||
@@ -150,8 +153,7 @@ mod tests {
|
|||||||
pubkey: std::string::String::from("SomePubkey"),
|
pubkey: std::string::String::from("SomePubkey"),
|
||||||
context_slot: 100,
|
context_slot: 100,
|
||||||
token_program_family: std::string::String::from("spl-token"),
|
token_program_family: std::string::String::from("spl-token"),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
let result = super::classify_domain_event(&event);
|
let result = super::classify_domain_event(&event);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let classified_option = result.expect("classify token event");
|
let classified_option = result.expect("classify token event");
|
||||||
@@ -160,10 +162,10 @@ mod tests {
|
|||||||
super::KhbbClassifiedDomainEvent::SplTokenProgramActivity(inner) => {
|
super::KhbbClassifiedDomainEvent::SplTokenProgramActivity(inner) => {
|
||||||
assert_eq!(inner.pubkey, "SomePubkey");
|
assert_eq!(inner.pubkey, "SomePubkey");
|
||||||
assert_eq!(inner.context_slot, 100);
|
assert_eq!(inner.context_slot, 100);
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!("expected spl-token classified event");
|
panic!("expected spl-token classified event");
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,10 +199,10 @@ mod tests {
|
|||||||
assert_eq!(inner.signature, "sig-1");
|
assert_eq!(inner.signature, "sig-1");
|
||||||
assert_eq!(inner.context_slot, 200);
|
assert_eq!(inner.context_slot, 200);
|
||||||
assert_eq!(inner.programs.len(), 2);
|
assert_eq!(inner.programs.len(), 2);
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!("expected known program log activity");
|
panic!("expected known program log activity");
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,10 +231,10 @@ mod tests {
|
|||||||
assert_eq!(inner.signature, "sig-2");
|
assert_eq!(inner.signature, "sig-2");
|
||||||
assert!(inner.has_error);
|
assert!(inner.has_error);
|
||||||
assert_eq!(inner.log_count, 1);
|
assert_eq!(inner.log_count, 1);
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!("expected unknown program log activity");
|
panic!("expected unknown program log activity");
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
181
khbb_lib/src/heuristics.rs
Normal file
181
khbb_lib/src/heuristics.rs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// file: khbb_lib/src/heuristics.rs
|
||||||
|
|
||||||
|
//! Early heuristic signals derived from classified domain events.
|
||||||
|
|
||||||
|
/// Early heuristic signal derived from classified activity.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum KhbbHeuristicSignal {
|
||||||
|
/// Potential token account creation or initialization activity.
|
||||||
|
PotentialTokenAccountActivity(KhbbPotentialTokenAccountActivitySignal),
|
||||||
|
/// Potential mint-related activity.
|
||||||
|
PotentialMintActivity(KhbbPotentialMintActivitySignal),
|
||||||
|
/// Potential initial transaction activity around a token account.
|
||||||
|
PotentialInitialTokenActivity(KhbbPotentialInitialTokenActivitySignal),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Heuristic signal indicating potential token account activity.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct KhbbPotentialTokenAccountActivitySignal {
|
||||||
|
/// Account pubkey involved in the signal.
|
||||||
|
pub pubkey: std::string::String,
|
||||||
|
/// Context slot.
|
||||||
|
pub context_slot: u64,
|
||||||
|
/// Subscription identifier.
|
||||||
|
pub subscription_id: u64,
|
||||||
|
/// Token program family.
|
||||||
|
pub token_program_family: std::string::String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Heuristic signal indicating potential mint-related activity.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct KhbbPotentialMintActivitySignal {
|
||||||
|
/// Account pubkey involved in the signal.
|
||||||
|
pub pubkey: std::string::String,
|
||||||
|
/// Context slot.
|
||||||
|
pub context_slot: u64,
|
||||||
|
/// Token program family.
|
||||||
|
pub token_program_family: std::string::String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Heuristic signal indicating a possibly relevant early transaction activity.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct KhbbPotentialInitialTokenActivitySignal {
|
||||||
|
/// Transaction signature.
|
||||||
|
pub signature: std::string::String,
|
||||||
|
/// Context slot.
|
||||||
|
pub context_slot: u64,
|
||||||
|
/// Whether the transaction errored.
|
||||||
|
pub has_error: bool,
|
||||||
|
/// Number of logs in the transaction.
|
||||||
|
pub log_count: usize,
|
||||||
|
/// Known programs seen in the logs.
|
||||||
|
pub programs: std::vec::Vec<crate::KhbbKnownProgram>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives early heuristic signals from classified domain events.
|
||||||
|
pub(crate) fn derive_heuristic_signals(
|
||||||
|
event: &crate::KhbbClassifiedDomainEvent,
|
||||||
|
) -> core::result::Result<std::vec::Vec<KhbbHeuristicSignal>, crate::KhbbError> {
|
||||||
|
match event {
|
||||||
|
crate::KhbbClassifiedDomainEvent::SplTokenProgramActivity(activity) => {
|
||||||
|
let mut signals = std::vec::Vec::<KhbbHeuristicSignal>::new();
|
||||||
|
signals.push(KhbbHeuristicSignal::PotentialTokenAccountActivity(
|
||||||
|
KhbbPotentialTokenAccountActivitySignal {
|
||||||
|
pubkey: activity.pubkey.clone(),
|
||||||
|
context_slot: activity.context_slot,
|
||||||
|
subscription_id: activity.subscription_id,
|
||||||
|
token_program_family: std::string::String::from("spl-token"),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
if activity.pubkey != crate::ids::WSOL_MINT_ID.to_string() {
|
||||||
|
signals.push(KhbbHeuristicSignal::PotentialMintActivity(
|
||||||
|
KhbbPotentialMintActivitySignal {
|
||||||
|
pubkey: activity.pubkey.clone(),
|
||||||
|
context_slot: activity.context_slot,
|
||||||
|
token_program_family: std::string::String::from("spl-token"),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(signals)
|
||||||
|
}
|
||||||
|
crate::KhbbClassifiedDomainEvent::SplToken2022ProgramActivity(activity) => {
|
||||||
|
let mut signals = std::vec::Vec::<KhbbHeuristicSignal>::new();
|
||||||
|
signals.push(KhbbHeuristicSignal::PotentialTokenAccountActivity(
|
||||||
|
KhbbPotentialTokenAccountActivitySignal {
|
||||||
|
pubkey: activity.pubkey.clone(),
|
||||||
|
context_slot: activity.context_slot,
|
||||||
|
subscription_id: activity.subscription_id,
|
||||||
|
token_program_family: std::string::String::from("spl-token-2022"),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
signals.push(KhbbHeuristicSignal::PotentialMintActivity(
|
||||||
|
KhbbPotentialMintActivitySignal {
|
||||||
|
pubkey: activity.pubkey.clone(),
|
||||||
|
context_slot: activity.context_slot,
|
||||||
|
token_program_family: std::string::String::from("spl-token-2022"),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
Ok(signals)
|
||||||
|
}
|
||||||
|
crate::KhbbClassifiedDomainEvent::KnownProgramLogActivity(activity) => {
|
||||||
|
let mut contains_token_program = false;
|
||||||
|
for program in &activity.programs {
|
||||||
|
match program {
|
||||||
|
crate::KhbbKnownProgram::SplToken
|
||||||
|
| crate::KhbbKnownProgram::SplToken2022
|
||||||
|
| crate::KhbbKnownProgram::AssociatedTokenAccount => {
|
||||||
|
contains_token_program = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !contains_token_program {
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
Ok(vec![KhbbHeuristicSignal::PotentialInitialTokenActivity(
|
||||||
|
KhbbPotentialInitialTokenActivitySignal {
|
||||||
|
signature: activity.signature.clone(),
|
||||||
|
context_slot: activity.context_slot,
|
||||||
|
has_error: activity.has_error,
|
||||||
|
log_count: activity.programs.len(),
|
||||||
|
programs: activity.programs.clone(),
|
||||||
|
},
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
crate::KhbbClassifiedDomainEvent::UnknownProgramLogActivity(_) => Ok(vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn derive_heuristics_from_spl_token_program_activity_returns_signals() {
|
||||||
|
let event = crate::KhbbClassifiedDomainEvent::SplTokenProgramActivity(
|
||||||
|
crate::KhbbSplTokenProgramActivityEvent {
|
||||||
|
pubkey: std::string::String::from("SomeTokenAccountPubkey"),
|
||||||
|
context_slot: 100,
|
||||||
|
subscription_id: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let result = super::derive_heuristic_signals(&event);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
let signals = result.expect("derive spl-token signals");
|
||||||
|
assert_eq!(signals.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_heuristics_from_known_program_logs_returns_signal_when_token_program_seen() {
|
||||||
|
let event = crate::KhbbClassifiedDomainEvent::KnownProgramLogActivity(
|
||||||
|
crate::KhbbKnownProgramLogActivityEvent {
|
||||||
|
signature: std::string::String::from("sig-1"),
|
||||||
|
context_slot: 200,
|
||||||
|
has_error: false,
|
||||||
|
programs: vec![
|
||||||
|
crate::KhbbKnownProgram::ComputeBudget,
|
||||||
|
crate::KhbbKnownProgram::SplToken,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let result = super::derive_heuristic_signals(&event);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
let signals = result.expect("derive known program log signals");
|
||||||
|
assert_eq!(signals.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_heuristics_from_unknown_program_logs_returns_no_signal() {
|
||||||
|
let event = crate::KhbbClassifiedDomainEvent::UnknownProgramLogActivity(
|
||||||
|
crate::KhbbUnknownProgramLogActivityEvent {
|
||||||
|
signature: std::string::String::from("sig-2"),
|
||||||
|
context_slot: 300,
|
||||||
|
has_error: false,
|
||||||
|
log_count: 2,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let result = super::derive_heuristic_signals(&event);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
let signals = result.expect("derive unknown log signals");
|
||||||
|
assert!(signals.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
22
khbb_lib/src/ids.rs
Normal file
22
khbb_lib/src/ids.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// file: khbb_lib/src/ids.rs
|
||||||
|
|
||||||
|
//! Centralized official Solana and SPL program identifiers.
|
||||||
|
|
||||||
|
/// SPL Token program (legacy).
|
||||||
|
pub const SPL_TOKEN_PROGRAM_ID: solana_sdk::pubkey::Pubkey = spl_token_interface::ID;
|
||||||
|
|
||||||
|
/// SPL Token-2022 program.
|
||||||
|
pub const SPL_TOKEN_2022_PROGRAM_ID: solana_sdk::pubkey::Pubkey = spl_token_2022_interface::ID;
|
||||||
|
|
||||||
|
/// Associated Token Account program.
|
||||||
|
pub const ASSOCIATED_TOKEN_PROGRAM_ID: solana_sdk::pubkey::Pubkey =
|
||||||
|
spl_associated_token_account_interface::program::ID;
|
||||||
|
|
||||||
|
/// Wrapped SOL mint.
|
||||||
|
pub const WSOL_MINT_ID: solana_sdk::pubkey::Pubkey = spl_token_interface::native_mint::ID;
|
||||||
|
|
||||||
|
/// System program.
|
||||||
|
pub const SYSTEM_PROGRAM_ID: solana_sdk::pubkey::Pubkey = solana_sdk_ids::system_program::ID;
|
||||||
|
|
||||||
|
/// Compute Budget program.
|
||||||
|
pub const COMPUTE_BUDGET_PROGRAM_ID: solana_sdk::pubkey::Pubkey = solana_sdk_ids::compute_budget::ID;
|
||||||
@@ -22,6 +22,8 @@ mod ws_event;
|
|||||||
mod domain_event;
|
mod domain_event;
|
||||||
mod program_registry;
|
mod program_registry;
|
||||||
mod domain_classifier;
|
mod domain_classifier;
|
||||||
|
mod ids;
|
||||||
|
mod heuristics;
|
||||||
|
|
||||||
/// Runs the listener application bootstrap workflow.
|
/// Runs the listener application bootstrap workflow.
|
||||||
pub use crate::app::run_listener_app;
|
pub use crate::app::run_listener_app;
|
||||||
@@ -97,3 +99,13 @@ pub use crate::domain_classifier::KhbbSplToken2022ProgramActivityEvent;
|
|||||||
pub use crate::domain_classifier::KhbbKnownProgramLogActivityEvent;
|
pub use crate::domain_classifier::KhbbKnownProgramLogActivityEvent;
|
||||||
/// Classified log activity not matching any known program.
|
/// Classified log activity not matching any known program.
|
||||||
pub use crate::domain_classifier::KhbbUnknownProgramLogActivityEvent;
|
pub use crate::domain_classifier::KhbbUnknownProgramLogActivityEvent;
|
||||||
|
/// Re-exeport official Solana and SPL program identifiers
|
||||||
|
pub use crate::ids::*;
|
||||||
|
/// Early heuristic signal derived from classified activity.
|
||||||
|
pub use crate::heuristics::KhbbHeuristicSignal;
|
||||||
|
/// Heuristic signal indicating potential token account activity.
|
||||||
|
pub use crate::heuristics::KhbbPotentialTokenAccountActivitySignal;
|
||||||
|
/// Heuristic signal indicating potential mint-related activity.
|
||||||
|
pub use crate::heuristics::KhbbPotentialMintActivitySignal;
|
||||||
|
/// Heuristic signal indicating a possibly relevant early transaction activity.
|
||||||
|
pub use crate::heuristics::KhbbPotentialInitialTokenActivitySignal;
|
||||||
|
|||||||
@@ -458,6 +458,40 @@ pub async fn run_listener_runtime(
|
|||||||
programs = ?classified.programs,
|
programs = ?classified.programs,
|
||||||
"classified known program log activity event"
|
"classified known program log activity event"
|
||||||
);
|
);
|
||||||
|
let heuristic_result =
|
||||||
|
crate::heuristics::derive_heuristic_signals(
|
||||||
|
&crate::KhbbClassifiedDomainEvent::KnownProgramLogActivity(
|
||||||
|
classified.clone(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
match heuristic_result {
|
||||||
|
Ok(signals) => {
|
||||||
|
for signal in signals {
|
||||||
|
match signal {
|
||||||
|
crate::KhbbHeuristicSignal::PotentialInitialTokenActivity(inner) => {
|
||||||
|
tracing::trace!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
signature = %inner.signature,
|
||||||
|
context_slot = inner.context_slot,
|
||||||
|
has_error = inner.has_error,
|
||||||
|
log_count = inner.log_count,
|
||||||
|
programs = ?inner.programs,
|
||||||
|
"heuristic potential initial token activity signal"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
crate::KhbbHeuristicSignal::PotentialTokenAccountActivity(_) => {}
|
||||||
|
crate::KhbbHeuristicSignal::PotentialMintActivity(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
tracing::error!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
error = %error,
|
||||||
|
"failed to derive heuristic signals from known program log activity"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(crate::KhbbClassifiedDomainEvent::UnknownProgramLogActivity(classified))) => {
|
Ok(Some(crate::KhbbClassifiedDomainEvent::UnknownProgramLogActivity(classified))) => {
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
@@ -506,6 +540,47 @@ pub async fn run_listener_runtime(
|
|||||||
context_slot = classified.context_slot,
|
context_slot = classified.context_slot,
|
||||||
"classified spl-token program activity event"
|
"classified spl-token program activity event"
|
||||||
);
|
);
|
||||||
|
let heuristic_result =
|
||||||
|
crate::heuristics::derive_heuristic_signals(
|
||||||
|
&crate::KhbbClassifiedDomainEvent::SplTokenProgramActivity(
|
||||||
|
classified.clone(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
match heuristic_result {
|
||||||
|
Ok(signals) => {
|
||||||
|
for signal in signals {
|
||||||
|
match signal {
|
||||||
|
crate::KhbbHeuristicSignal::PotentialTokenAccountActivity(inner) => {
|
||||||
|
tracing::trace!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
pubkey = %inner.pubkey,
|
||||||
|
context_slot = inner.context_slot,
|
||||||
|
subscription_id = inner.subscription_id,
|
||||||
|
token_program_family = %inner.token_program_family,
|
||||||
|
"heuristic potential token account activity signal"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
crate::KhbbHeuristicSignal::PotentialMintActivity(inner) => {
|
||||||
|
tracing::trace!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
pubkey = %inner.pubkey,
|
||||||
|
context_slot = inner.context_slot,
|
||||||
|
token_program_family = %inner.token_program_family,
|
||||||
|
"heuristic potential mint activity signal"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
crate::KhbbHeuristicSignal::PotentialInitialTokenActivity(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
tracing::error!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
error = %error,
|
||||||
|
"failed to derive heuristic signals from spl-token program activity"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(crate::KhbbClassifiedDomainEvent::SplToken2022ProgramActivity(classified))) => {
|
Ok(Some(crate::KhbbClassifiedDomainEvent::SplToken2022ProgramActivity(classified))) => {
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
@@ -515,6 +590,47 @@ pub async fn run_listener_runtime(
|
|||||||
context_slot = classified.context_slot,
|
context_slot = classified.context_slot,
|
||||||
"classified spl-token-2022 program activity event"
|
"classified spl-token-2022 program activity event"
|
||||||
);
|
);
|
||||||
|
let heuristic_result =
|
||||||
|
crate::heuristics::derive_heuristic_signals(
|
||||||
|
&crate::KhbbClassifiedDomainEvent::SplToken2022ProgramActivity(
|
||||||
|
classified.clone(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
match heuristic_result {
|
||||||
|
Ok(signals) => {
|
||||||
|
for signal in signals {
|
||||||
|
match signal {
|
||||||
|
crate::KhbbHeuristicSignal::PotentialTokenAccountActivity(inner) => {
|
||||||
|
tracing::trace!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
pubkey = %inner.pubkey,
|
||||||
|
context_slot = inner.context_slot,
|
||||||
|
subscription_id = inner.subscription_id,
|
||||||
|
token_program_family = %inner.token_program_family,
|
||||||
|
"heuristic potential token account activity signal"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
crate::KhbbHeuristicSignal::PotentialMintActivity(inner) => {
|
||||||
|
tracing::trace!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
pubkey = %inner.pubkey,
|
||||||
|
context_slot = inner.context_slot,
|
||||||
|
token_program_family = %inner.token_program_family,
|
||||||
|
"heuristic potential mint activity signal"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
crate::KhbbHeuristicSignal::PotentialInitialTokenActivity(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
tracing::error!(
|
||||||
|
listener_session_id = session.id,
|
||||||
|
error = %error,
|
||||||
|
"failed to derive heuristic signals from spl-token-2022 program activity"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(_)) => {}
|
Ok(Some(_)) => {}
|
||||||
Ok(None) => {}
|
Ok(None) => {}
|
||||||
|
|||||||
@@ -18,17 +18,32 @@ pub enum KhbbKnownProgram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the known program classification for a given program id.
|
/// Returns the known program classification for a given program id.
|
||||||
pub(crate) fn classify_known_program_id(program_id: &str) -> std::option::Option<KhbbKnownProgram> {
|
pub(crate) fn classify_known_program_id(
|
||||||
match program_id {
|
program_id: &str,
|
||||||
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" => Some(KhbbKnownProgram::SplToken),
|
) -> std::option::Option<KhbbKnownProgram> {
|
||||||
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" => Some(KhbbKnownProgram::SplToken2022),
|
let parse_result = program_id.parse::<solana_sdk::pubkey::Pubkey>();
|
||||||
"11111111111111111111111111111111" => Some(KhbbKnownProgram::System),
|
let pubkey = match parse_result {
|
||||||
"ComputeBudget111111111111111111111111111111" => Some(KhbbKnownProgram::ComputeBudget),
|
Ok(value) => value,
|
||||||
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" => {
|
Err(_) => {
|
||||||
Some(KhbbKnownProgram::AssociatedTokenAccount)
|
return None;
|
||||||
},
|
}
|
||||||
_ => None,
|
};
|
||||||
|
if pubkey == crate::SPL_TOKEN_PROGRAM_ID {
|
||||||
|
return Some(KhbbKnownProgram::SplToken);
|
||||||
}
|
}
|
||||||
|
if pubkey == crate::SPL_TOKEN_2022_PROGRAM_ID {
|
||||||
|
return Some(KhbbKnownProgram::SplToken2022);
|
||||||
|
}
|
||||||
|
if pubkey == crate::SYSTEM_PROGRAM_ID {
|
||||||
|
return Some(KhbbKnownProgram::System);
|
||||||
|
}
|
||||||
|
if pubkey == crate::COMPUTE_BUDGET_PROGRAM_ID {
|
||||||
|
return Some(KhbbKnownProgram::ComputeBudget);
|
||||||
|
}
|
||||||
|
if pubkey == crate::ASSOCIATED_TOKEN_PROGRAM_ID {
|
||||||
|
return Some(KhbbKnownProgram::AssociatedTokenAccount);
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Detects known program mentions in a transaction log line.
|
/// Detects known program mentions in a transaction log line.
|
||||||
|
|||||||
Reference in New Issue
Block a user