0.7.34
This commit is contained in:
@@ -25,10 +25,10 @@ mod pair_candle;
|
||||
mod pair_metric;
|
||||
mod pool;
|
||||
mod pool_listing;
|
||||
mod pool_lifecycle_event;
|
||||
mod pool_origin;
|
||||
mod pool_token;
|
||||
mod program_instruction_diagnostic;
|
||||
mod program_instruction_discriminator_summary;
|
||||
mod protocol_candidate;
|
||||
mod protocol_candidate_summary;
|
||||
mod swap;
|
||||
@@ -39,22 +39,24 @@ mod trade_event;
|
||||
mod transaction_classification;
|
||||
mod wallet;
|
||||
mod wallet_holding;
|
||||
mod program_instruction_discriminator_summary;
|
||||
mod wallet_participation;
|
||||
|
||||
pub(crate) use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalDexDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalNonActionablePairDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPairActionabilityDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPairDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPairActionabilityDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPairTradingReadinessDiagnosticSummaryRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleRow;
|
||||
pub(crate) use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersRow;
|
||||
|
||||
pub use program_instruction_discriminator_summary::ProgramInstructionDiscriminatorSummaryDto;
|
||||
pub use analysis_signal::AnalysisSignalDto;
|
||||
pub use chain_instruction::ChainInstructionDto;
|
||||
pub use chain_slot::ChainSlotDto;
|
||||
@@ -70,17 +72,17 @@ pub use launch_surface::LaunchSurfaceDto;
|
||||
pub use launch_surface_key::LaunchSurfaceKeyDto;
|
||||
pub use liquidity_event::LiquidityEventDto;
|
||||
pub use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalDexDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
||||
pub use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleDto;
|
||||
pub use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
||||
pub use local_pipeline_diagnostics::LocalNonActionablePairDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalPairActionabilityDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalPairDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleDto;
|
||||
pub use local_pipeline_diagnostics::LocalPairActionabilityDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalPairTradingReadinessDiagnosticSummaryDto;
|
||||
pub use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleDto;
|
||||
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersDto;
|
||||
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticSummaryDto;
|
||||
pub use observed_token::ObservedTokenDto;
|
||||
@@ -91,10 +93,10 @@ pub use pair_candle::PairCandleDto;
|
||||
pub use pair_metric::PairMetricDto;
|
||||
pub use pool::PoolDto;
|
||||
pub use pool_listing::PoolListingDto;
|
||||
pub use pool_lifecycle_event::PoolLifecycleEventDto;
|
||||
pub use pool_origin::PoolOriginDto;
|
||||
pub use pool_token::PoolTokenDto;
|
||||
pub use program_instruction_diagnostic::ProgramInstructionDiagnosticDto;
|
||||
pub use program_instruction_discriminator_summary::ProgramInstructionDiscriminatorSummaryDto;
|
||||
pub use protocol_candidate::ProtocolCandidateDto;
|
||||
pub use protocol_candidate_summary::ProtocolCandidateSummaryDto;
|
||||
pub use swap::SwapDto;
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
pub struct LiquidityEventDto {
|
||||
/// Optional numeric primary key.
|
||||
pub id: std::option::Option<i64>,
|
||||
/// Optional related transaction id.
|
||||
pub transaction_id: std::option::Option<i64>,
|
||||
/// Optional related decoded DEX event id.
|
||||
pub decoded_event_id: std::option::Option<i64>,
|
||||
/// Related DEX id.
|
||||
pub dex_id: i64,
|
||||
/// Related pool id.
|
||||
@@ -19,8 +23,12 @@ pub struct LiquidityEventDto {
|
||||
pub instruction_index: i64,
|
||||
/// Optional slot number.
|
||||
pub slot: std::option::Option<u64>,
|
||||
/// Optional program id that emitted the decoded event.
|
||||
pub program_id: std::option::Option<std::string::String>,
|
||||
/// Liquidity event kind.
|
||||
pub event_kind: crate::LiquidityEventKind,
|
||||
/// Optional original decoded event kind.
|
||||
pub event_kind_text: std::option::Option<std::string::String>,
|
||||
/// Optional actor wallet.
|
||||
pub actor_wallet: std::option::Option<std::string::String>,
|
||||
/// Base token id.
|
||||
@@ -35,8 +43,14 @@ pub struct LiquidityEventDto {
|
||||
pub quote_amount: std::string::String,
|
||||
/// Optional LP amount as decimal text.
|
||||
pub lp_amount: std::option::Option<std::string::String>,
|
||||
/// Whether the persisted amount fields are complete.
|
||||
pub amounts_are_complete: bool,
|
||||
/// Optional source decoded payload JSON.
|
||||
pub payload_json: std::option::Option<std::string::String>,
|
||||
/// Execution timestamp.
|
||||
pub executed_at: chrono::DateTime<chrono::Utc>,
|
||||
/// Creation timestamp.
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
impl LiquidityEventDto {
|
||||
@@ -57,15 +71,20 @@ impl LiquidityEventDto {
|
||||
quote_amount: std::string::String,
|
||||
lp_amount: std::option::Option<std::string::String>,
|
||||
) -> Self {
|
||||
let now = chrono::Utc::now();
|
||||
return Self {
|
||||
id: None,
|
||||
transaction_id: None,
|
||||
decoded_event_id: None,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
instruction_index,
|
||||
slot,
|
||||
program_id: None,
|
||||
event_kind,
|
||||
event_kind_text: None,
|
||||
actor_wallet,
|
||||
base_token_id,
|
||||
quote_token_id,
|
||||
@@ -73,9 +92,32 @@ impl LiquidityEventDto {
|
||||
base_amount,
|
||||
quote_amount,
|
||||
lp_amount,
|
||||
executed_at: chrono::Utc::now(),
|
||||
amounts_are_complete: true,
|
||||
payload_json: None,
|
||||
executed_at: now,
|
||||
created_at: now,
|
||||
};
|
||||
}
|
||||
|
||||
/// Adds decoded-event linkage and audit payload metadata to the DTO.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn with_decoded_event_metadata(
|
||||
mut self,
|
||||
transaction_id: std::option::Option<i64>,
|
||||
decoded_event_id: std::option::Option<i64>,
|
||||
program_id: std::option::Option<std::string::String>,
|
||||
event_kind_text: std::option::Option<std::string::String>,
|
||||
payload_json: std::option::Option<std::string::String>,
|
||||
amounts_are_complete: bool,
|
||||
) -> Self {
|
||||
self.transaction_id = transaction_id;
|
||||
self.decoded_event_id = decoded_event_id;
|
||||
self.program_id = program_id;
|
||||
self.event_kind_text = event_kind_text;
|
||||
self.payload_json = payload_json;
|
||||
self.amounts_are_complete = amounts_are_complete;
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::LiquidityEventEntity> for LiquidityEventDto {
|
||||
@@ -114,13 +156,17 @@ impl TryFrom<crate::LiquidityEventEntity> for LiquidityEventDto {
|
||||
};
|
||||
return Ok(Self {
|
||||
id: Some(entity.id),
|
||||
transaction_id: entity.transaction_id,
|
||||
decoded_event_id: entity.decoded_event_id,
|
||||
dex_id: entity.dex_id,
|
||||
pool_id: entity.pool_id,
|
||||
pair_id: entity.pair_id,
|
||||
signature: entity.signature,
|
||||
instruction_index: entity.instruction_index,
|
||||
slot,
|
||||
program_id: entity.program_id,
|
||||
event_kind,
|
||||
event_kind_text: entity.event_kind_text,
|
||||
actor_wallet: entity.actor_wallet,
|
||||
base_token_id: entity.base_token_id,
|
||||
quote_token_id: entity.quote_token_id,
|
||||
@@ -128,7 +174,27 @@ impl TryFrom<crate::LiquidityEventEntity> for LiquidityEventDto {
|
||||
base_amount: entity.base_amount,
|
||||
quote_amount: entity.quote_amount,
|
||||
lp_amount: entity.lp_amount,
|
||||
amounts_are_complete: match entity.amounts_are_complete {
|
||||
Some(amounts_are_complete) => amounts_are_complete != 0,
|
||||
None => true,
|
||||
},
|
||||
payload_json: entity.payload_json,
|
||||
executed_at,
|
||||
created_at: match entity.created_at {
|
||||
Some(created_at) => {
|
||||
let created_at_result = chrono::DateTime::parse_from_rfc3339(&created_at);
|
||||
match created_at_result {
|
||||
Ok(created_at) => created_at.with_timezone(&chrono::Utc),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot parse liquidity event created_at '{}': {}",
|
||||
created_at, error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
None => executed_at,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ pub struct LocalPipelineDiagnosticSummaryDto {
|
||||
pub decoded_non_actionable_trade_event_count: i64,
|
||||
/// Total decoded events with unknown classification.
|
||||
pub decoded_unknown_event_count: i64,
|
||||
/// Total persisted liquidity events.
|
||||
pub liquidity_event_count: i64,
|
||||
/// Total persisted pool lifecycle events.
|
||||
pub pool_lifecycle_event_count: i64,
|
||||
/// Whether the local persisted pipeline has no blocking diagnostic issue.
|
||||
pub diagnostics_clean: bool,
|
||||
/// Number of blocking diagnostic issues.
|
||||
@@ -363,6 +367,10 @@ pub struct LocalPipelineDiagnosticCountersDto {
|
||||
pub decoded_non_actionable_trade_event_count: i64,
|
||||
/// Total decoded events with unknown classification.
|
||||
pub decoded_unknown_event_count: i64,
|
||||
/// Total persisted liquidity events.
|
||||
pub liquidity_event_count: i64,
|
||||
/// Total persisted pool lifecycle events.
|
||||
pub pool_lifecycle_event_count: i64,
|
||||
/// Total decoded trade candidates without trade event, including ignored failed transactions.
|
||||
pub missing_trade_event_count: i64,
|
||||
/// Explicit alias for decoded trade candidates without linked trade event.
|
||||
@@ -433,6 +441,8 @@ pub(crate) struct LocalPipelineDiagnosticCountersRow {
|
||||
pub(crate) decoded_non_trade_useful_event_count: i64,
|
||||
pub(crate) decoded_non_actionable_trade_event_count: i64,
|
||||
pub(crate) decoded_unknown_event_count: i64,
|
||||
pub(crate) liquidity_event_count: i64,
|
||||
pub(crate) pool_lifecycle_event_count: i64,
|
||||
pub(crate) missing_trade_event_count: i64,
|
||||
pub(crate) decoded_trade_candidate_without_trade_event_count: i64,
|
||||
pub(crate) decoded_trade_candidate_without_trade_event_on_ok_transaction_count: i64,
|
||||
|
||||
145
kb_lib/src/db/dtos/pool_lifecycle_event.rs
Normal file
145
kb_lib/src/db/dtos/pool_lifecycle_event.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
// file: kb_lib/src/db/dtos/pool_lifecycle_event.rs
|
||||
|
||||
//! Pool lifecycle event DTO.
|
||||
|
||||
/// Application-facing normalized pool lifecycle event DTO.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PoolLifecycleEventDto {
|
||||
/// Optional numeric primary key.
|
||||
pub id: std::option::Option<i64>,
|
||||
/// Related transaction id.
|
||||
pub transaction_id: i64,
|
||||
/// Related decoded DEX event id, when available.
|
||||
pub decoded_event_id: std::option::Option<i64>,
|
||||
/// Related DEX id, when the DEX row is known.
|
||||
pub dex_id: std::option::Option<i64>,
|
||||
/// Related pool id, when the pool row is known.
|
||||
pub pool_id: std::option::Option<i64>,
|
||||
/// Related pair id, when the pair row is known.
|
||||
pub pair_id: std::option::Option<i64>,
|
||||
/// Transaction signature.
|
||||
pub signature: std::string::String,
|
||||
/// Optional slot number.
|
||||
pub slot: std::option::Option<u64>,
|
||||
/// Protocol name that emitted the decoded event.
|
||||
pub protocol_name: std::string::String,
|
||||
/// Program id that emitted the decoded event.
|
||||
pub program_id: std::string::String,
|
||||
/// Stable decoded event kind.
|
||||
pub event_kind: std::string::String,
|
||||
/// Pool account address, when decoded.
|
||||
pub pool_account: std::option::Option<std::string::String>,
|
||||
/// First token mint, when decoded.
|
||||
pub token_a_mint: std::option::Option<std::string::String>,
|
||||
/// Second token mint, when decoded.
|
||||
pub token_b_mint: std::option::Option<std::string::String>,
|
||||
/// Source decoded payload JSON.
|
||||
pub payload_json: std::string::String,
|
||||
/// Execution timestamp.
|
||||
pub executed_at: chrono::DateTime<chrono::Utc>,
|
||||
/// Creation timestamp.
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
impl PoolLifecycleEventDto {
|
||||
/// Creates a new pool lifecycle event DTO.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
transaction_id: i64,
|
||||
decoded_event_id: std::option::Option<i64>,
|
||||
dex_id: std::option::Option<i64>,
|
||||
pool_id: std::option::Option<i64>,
|
||||
pair_id: std::option::Option<i64>,
|
||||
signature: std::string::String,
|
||||
slot: std::option::Option<u64>,
|
||||
protocol_name: std::string::String,
|
||||
program_id: std::string::String,
|
||||
event_kind: std::string::String,
|
||||
pool_account: std::option::Option<std::string::String>,
|
||||
token_a_mint: std::option::Option<std::string::String>,
|
||||
token_b_mint: std::option::Option<std::string::String>,
|
||||
payload_json: std::string::String,
|
||||
) -> Self {
|
||||
let now = chrono::Utc::now();
|
||||
return Self {
|
||||
id: None,
|
||||
transaction_id,
|
||||
decoded_event_id,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
slot,
|
||||
protocol_name,
|
||||
program_id,
|
||||
event_kind,
|
||||
pool_account,
|
||||
token_a_mint,
|
||||
token_b_mint,
|
||||
payload_json,
|
||||
executed_at: now,
|
||||
created_at: now,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::PoolLifecycleEventEntity> for PoolLifecycleEventDto {
|
||||
type Error = crate::Error;
|
||||
|
||||
fn try_from(entity: crate::PoolLifecycleEventEntity) -> Result<Self, Self::Error> {
|
||||
let executed_at_result = chrono::DateTime::parse_from_rfc3339(&entity.executed_at);
|
||||
let executed_at = match executed_at_result {
|
||||
Ok(executed_at) => executed_at.with_timezone(&chrono::Utc),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot parse pool lifecycle event executed_at '{}': {}",
|
||||
entity.executed_at, error
|
||||
)));
|
||||
},
|
||||
};
|
||||
let created_at_result = chrono::DateTime::parse_from_rfc3339(&entity.created_at);
|
||||
let created_at = match created_at_result {
|
||||
Ok(created_at) => created_at.with_timezone(&chrono::Utc),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot parse pool lifecycle event created_at '{}': {}",
|
||||
entity.created_at, error
|
||||
)));
|
||||
},
|
||||
};
|
||||
let slot = match entity.slot {
|
||||
Some(slot) => {
|
||||
let slot_result = u64::try_from(slot);
|
||||
match slot_result {
|
||||
Ok(slot) => Some(slot),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot convert pool lifecycle event slot '{}' to u64: {}",
|
||||
slot, error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
return Ok(Self {
|
||||
id: Some(entity.id),
|
||||
transaction_id: entity.transaction_id,
|
||||
decoded_event_id: entity.decoded_event_id,
|
||||
dex_id: entity.dex_id,
|
||||
pool_id: entity.pool_id,
|
||||
pair_id: entity.pair_id,
|
||||
signature: entity.signature,
|
||||
slot,
|
||||
protocol_name: entity.protocol_name,
|
||||
program_id: entity.program_id,
|
||||
event_kind: entity.event_kind,
|
||||
pool_account: entity.pool_account,
|
||||
token_a_mint: entity.token_a_mint,
|
||||
token_b_mint: entity.token_b_mint,
|
||||
payload_json: entity.payload_json,
|
||||
executed_at,
|
||||
created_at,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ mod pair_candle;
|
||||
mod pair_metric;
|
||||
mod pool;
|
||||
mod pool_listing;
|
||||
mod pool_lifecycle_event;
|
||||
mod pool_origin;
|
||||
mod pool_token;
|
||||
mod program_instruction_diagnostic;
|
||||
@@ -64,6 +65,7 @@ pub use pair_candle::PairCandleEntity;
|
||||
pub use pair_metric::PairMetricEntity;
|
||||
pub use pool::PoolEntity;
|
||||
pub use pool_listing::PoolListingEntity;
|
||||
pub use pool_lifecycle_event::PoolLifecycleEventEntity;
|
||||
pub use pool_origin::PoolOriginEntity;
|
||||
pub use pool_token::PoolTokenEntity;
|
||||
pub use program_instruction_diagnostic::ProgramInstructionDiagnosticEntity;
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
pub struct LiquidityEventEntity {
|
||||
/// Numeric primary key.
|
||||
pub id: i64,
|
||||
/// Optional related transaction id.
|
||||
pub transaction_id: std::option::Option<i64>,
|
||||
/// Optional related decoded DEX event id.
|
||||
pub decoded_event_id: std::option::Option<i64>,
|
||||
/// Related DEX id.
|
||||
pub dex_id: i64,
|
||||
/// Related pool id.
|
||||
@@ -19,8 +23,12 @@ pub struct LiquidityEventEntity {
|
||||
pub instruction_index: i64,
|
||||
/// Optional slot number.
|
||||
pub slot: std::option::Option<i64>,
|
||||
/// Optional program id that emitted the decoded event.
|
||||
pub program_id: std::option::Option<std::string::String>,
|
||||
/// Event kind stored as stable integer.
|
||||
pub event_kind: i16,
|
||||
/// Optional original decoded event kind.
|
||||
pub event_kind_text: std::option::Option<std::string::String>,
|
||||
/// Optional actor wallet.
|
||||
pub actor_wallet: std::option::Option<std::string::String>,
|
||||
/// Base token id.
|
||||
@@ -35,6 +43,12 @@ pub struct LiquidityEventEntity {
|
||||
pub quote_amount: std::string::String,
|
||||
/// Optional LP amount as decimal text.
|
||||
pub lp_amount: std::option::Option<std::string::String>,
|
||||
/// Whether the persisted amount fields are complete.
|
||||
pub amounts_are_complete: std::option::Option<i64>,
|
||||
/// Optional source decoded payload JSON.
|
||||
pub payload_json: std::option::Option<std::string::String>,
|
||||
/// Execution timestamp encoded as RFC3339 UTC text.
|
||||
pub executed_at: std::string::String,
|
||||
/// Optional creation timestamp encoded as RFC3339 UTC text.
|
||||
pub created_at: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
42
kb_lib/src/db/entities/pool_lifecycle_event.rs
Normal file
42
kb_lib/src/db/entities/pool_lifecycle_event.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
// file: kb_lib/src/db/entities/pool_lifecycle_event.rs
|
||||
|
||||
//! Pool lifecycle event entity.
|
||||
|
||||
/// Persisted normalized pool lifecycle event row.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, sqlx::FromRow)]
|
||||
pub struct PoolLifecycleEventEntity {
|
||||
/// Numeric primary key.
|
||||
pub id: i64,
|
||||
/// Related transaction id.
|
||||
pub transaction_id: i64,
|
||||
/// Related decoded DEX event id, when available.
|
||||
pub decoded_event_id: std::option::Option<i64>,
|
||||
/// Related DEX id, when the DEX row is known.
|
||||
pub dex_id: std::option::Option<i64>,
|
||||
/// Related pool id, when the pool row is known.
|
||||
pub pool_id: std::option::Option<i64>,
|
||||
/// Related pair id, when the pair row is known.
|
||||
pub pair_id: std::option::Option<i64>,
|
||||
/// Transaction signature.
|
||||
pub signature: std::string::String,
|
||||
/// Optional slot number.
|
||||
pub slot: std::option::Option<i64>,
|
||||
/// Protocol name that emitted the decoded event.
|
||||
pub protocol_name: std::string::String,
|
||||
/// Program id that emitted the decoded event.
|
||||
pub program_id: std::string::String,
|
||||
/// Stable decoded event kind.
|
||||
pub event_kind: std::string::String,
|
||||
/// Pool account address, when decoded.
|
||||
pub pool_account: std::option::Option<std::string::String>,
|
||||
/// First token mint, when decoded.
|
||||
pub token_a_mint: std::option::Option<std::string::String>,
|
||||
/// Second token mint, when decoded.
|
||||
pub token_b_mint: std::option::Option<std::string::String>,
|
||||
/// Source decoded payload JSON.
|
||||
pub payload_json: std::string::String,
|
||||
/// Execution timestamp encoded as RFC3339 UTC text.
|
||||
pub executed_at: std::string::String,
|
||||
/// Creation timestamp encoded as RFC3339 UTC text.
|
||||
pub created_at: std::string::String,
|
||||
}
|
||||
@@ -24,6 +24,7 @@ mod pair_analytic_signal;
|
||||
mod pair_candle;
|
||||
mod pair_metric;
|
||||
mod pool;
|
||||
mod pool_lifecycle_event;
|
||||
mod pool_listing;
|
||||
mod pool_origin;
|
||||
mod pool_token;
|
||||
@@ -116,6 +117,9 @@ pub use pair_metric::query_pair_metrics_upsert;
|
||||
pub use pool::query_pools_get_by_address;
|
||||
pub use pool::query_pools_list;
|
||||
pub use pool::query_pools_upsert;
|
||||
pub use pool_lifecycle_event::query_pool_lifecycle_events_get_by_decoded_event_id;
|
||||
pub use pool_lifecycle_event::query_pool_lifecycle_events_list_recent;
|
||||
pub use pool_lifecycle_event::query_pool_lifecycle_events_upsert;
|
||||
pub use pool_listing::query_pool_listings_get_by_pool_id;
|
||||
pub use pool_listing::query_pool_listings_list;
|
||||
pub use pool_listing::query_pool_listings_upsert;
|
||||
|
||||
@@ -27,13 +27,17 @@ pub async fn query_liquidity_events_upsert(
|
||||
let query_result = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO k_sol_liquidity_events (
|
||||
transaction_id,
|
||||
decoded_event_id,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
instruction_index,
|
||||
slot,
|
||||
program_id,
|
||||
event_kind,
|
||||
event_kind_text,
|
||||
actor_wallet,
|
||||
base_token_id,
|
||||
quote_token_id,
|
||||
@@ -41,15 +45,22 @@ INSERT INTO k_sol_liquidity_events (
|
||||
base_amount,
|
||||
quote_amount,
|
||||
lp_amount,
|
||||
executed_at
|
||||
amounts_are_complete,
|
||||
payload_json,
|
||||
executed_at,
|
||||
created_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(signature, instruction_index) DO UPDATE SET
|
||||
transaction_id = excluded.transaction_id,
|
||||
decoded_event_id = excluded.decoded_event_id,
|
||||
dex_id = excluded.dex_id,
|
||||
pool_id = excluded.pool_id,
|
||||
pair_id = excluded.pair_id,
|
||||
slot = excluded.slot,
|
||||
program_id = excluded.program_id,
|
||||
event_kind = excluded.event_kind,
|
||||
event_kind_text = excluded.event_kind_text,
|
||||
actor_wallet = excluded.actor_wallet,
|
||||
base_token_id = excluded.base_token_id,
|
||||
quote_token_id = excluded.quote_token_id,
|
||||
@@ -57,16 +68,22 @@ ON CONFLICT(signature, instruction_index) DO UPDATE SET
|
||||
base_amount = excluded.base_amount,
|
||||
quote_amount = excluded.quote_amount,
|
||||
lp_amount = excluded.lp_amount,
|
||||
amounts_are_complete = excluded.amounts_are_complete,
|
||||
payload_json = excluded.payload_json,
|
||||
executed_at = excluded.executed_at
|
||||
"#,
|
||||
)
|
||||
.bind(dto.transaction_id)
|
||||
.bind(dto.decoded_event_id)
|
||||
.bind(dto.dex_id)
|
||||
.bind(dto.pool_id)
|
||||
.bind(dto.pair_id)
|
||||
.bind(dto.signature.clone())
|
||||
.bind(dto.instruction_index)
|
||||
.bind(slot_i64)
|
||||
.bind(dto.program_id.clone())
|
||||
.bind(dto.event_kind.to_i16())
|
||||
.bind(dto.event_kind_text.clone())
|
||||
.bind(dto.actor_wallet.clone())
|
||||
.bind(dto.base_token_id)
|
||||
.bind(dto.quote_token_id)
|
||||
@@ -74,7 +91,10 @@ ON CONFLICT(signature, instruction_index) DO UPDATE SET
|
||||
.bind(dto.base_amount.clone())
|
||||
.bind(dto.quote_amount.clone())
|
||||
.bind(dto.lp_amount.clone())
|
||||
.bind(if dto.amounts_are_complete { 1_i64 } else { 0_i64 })
|
||||
.bind(dto.payload_json.clone())
|
||||
.bind(dto.executed_at.to_rfc3339())
|
||||
.bind(dto.created_at.to_rfc3339())
|
||||
.execute(pool)
|
||||
.await;
|
||||
if let Err(error) = query_result {
|
||||
@@ -122,13 +142,17 @@ pub async fn query_liquidity_events_list_recent(
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
transaction_id,
|
||||
decoded_event_id,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
instruction_index,
|
||||
slot,
|
||||
program_id,
|
||||
event_kind,
|
||||
event_kind_text,
|
||||
actor_wallet,
|
||||
base_token_id,
|
||||
quote_token_id,
|
||||
@@ -136,7 +160,10 @@ SELECT
|
||||
base_amount,
|
||||
quote_amount,
|
||||
lp_amount,
|
||||
executed_at
|
||||
amounts_are_complete,
|
||||
payload_json,
|
||||
executed_at,
|
||||
created_at
|
||||
FROM k_sol_liquidity_events
|
||||
ORDER BY id DESC
|
||||
LIMIT ?
|
||||
|
||||
@@ -48,6 +48,8 @@ SELECT
|
||||
FROM k_sol_dex_decoded_events
|
||||
WHERE COALESCE(json_extract(payload_json, '$.eventCategory'), 'unknown') = 'unknown'
|
||||
) AS decoded_unknown_event_count,
|
||||
(SELECT COUNT(*) FROM k_sol_liquidity_events) AS liquidity_event_count,
|
||||
(SELECT COUNT(*) FROM k_sol_pool_lifecycle_events) AS pool_lifecycle_event_count,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM k_sol_dex_decoded_events dde
|
||||
@@ -357,6 +359,8 @@ SELECT
|
||||
decoded_non_actionable_trade_event_count: row
|
||||
.decoded_non_actionable_trade_event_count,
|
||||
decoded_unknown_event_count: row.decoded_unknown_event_count,
|
||||
liquidity_event_count: row.liquidity_event_count,
|
||||
pool_lifecycle_event_count: row.pool_lifecycle_event_count,
|
||||
missing_trade_event_count: row.missing_trade_event_count,
|
||||
decoded_trade_candidate_without_trade_event_count: row
|
||||
.decoded_trade_candidate_without_trade_event_count,
|
||||
|
||||
294
kb_lib/src/db/queries/pool_lifecycle_event.rs
Normal file
294
kb_lib/src/db/queries/pool_lifecycle_event.rs
Normal file
@@ -0,0 +1,294 @@
|
||||
// file: kb_lib/src/db/queries/pool_lifecycle_event.rs
|
||||
|
||||
//! Queries for `k_sol_pool_lifecycle_events`.
|
||||
|
||||
/// Returns one pool lifecycle event by decoded event id.
|
||||
pub async fn query_pool_lifecycle_events_get_by_decoded_event_id(
|
||||
database: &crate::Database,
|
||||
decoded_event_id: i64,
|
||||
) -> Result<std::option::Option<crate::PoolLifecycleEventDto>, crate::Error> {
|
||||
match database.connection() {
|
||||
crate::DatabaseConnection::Sqlite(pool) => {
|
||||
let query_result = sqlx::query_as::<sqlx::Sqlite, crate::PoolLifecycleEventEntity>(
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
transaction_id,
|
||||
decoded_event_id,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
slot,
|
||||
protocol_name,
|
||||
program_id,
|
||||
event_kind,
|
||||
pool_account,
|
||||
token_a_mint,
|
||||
token_b_mint,
|
||||
payload_json,
|
||||
executed_at,
|
||||
created_at
|
||||
FROM k_sol_pool_lifecycle_events
|
||||
WHERE decoded_event_id = ?
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.bind(decoded_event_id)
|
||||
.fetch_optional(pool)
|
||||
.await;
|
||||
let entity_option = match query_result {
|
||||
Ok(entity_option) => entity_option,
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot fetch k_sol_pool_lifecycle_events by decoded_event_id '{}' on sqlite: {}",
|
||||
decoded_event_id, error
|
||||
)));
|
||||
},
|
||||
};
|
||||
match entity_option {
|
||||
Some(entity) => {
|
||||
let dto_result = crate::PoolLifecycleEventDto::try_from(entity);
|
||||
match dto_result {
|
||||
Ok(dto) => return Ok(Some(dto)),
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
},
|
||||
None => return Ok(None),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts or updates one normalized pool lifecycle event row.
|
||||
pub async fn query_pool_lifecycle_events_upsert(
|
||||
database: &crate::Database,
|
||||
dto: &crate::PoolLifecycleEventDto,
|
||||
) -> Result<i64, crate::Error> {
|
||||
let slot_i64 = match dto.slot {
|
||||
Some(slot) => {
|
||||
let slot_result = i64::try_from(slot);
|
||||
match slot_result {
|
||||
Ok(slot) => Some(slot),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot convert pool lifecycle event slot '{}' to i64: {}",
|
||||
slot, error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
match database.connection() {
|
||||
crate::DatabaseConnection::Sqlite(pool) => {
|
||||
let existing_id = match dto.decoded_event_id {
|
||||
Some(decoded_event_id) => {
|
||||
let existing_result = sqlx::query_scalar::<sqlx::Sqlite, i64>(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM k_sol_pool_lifecycle_events
|
||||
WHERE decoded_event_id = ?
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.bind(decoded_event_id)
|
||||
.fetch_optional(pool)
|
||||
.await;
|
||||
match existing_result {
|
||||
Ok(existing_id) => existing_id,
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot fetch k_sol_pool_lifecycle_events id for decoded_event_id '{}' on sqlite: {}",
|
||||
decoded_event_id, error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
if let Some(id) = existing_id {
|
||||
let update_result = sqlx::query(
|
||||
r#"
|
||||
UPDATE k_sol_pool_lifecycle_events
|
||||
SET
|
||||
transaction_id = ?,
|
||||
dex_id = ?,
|
||||
pool_id = ?,
|
||||
pair_id = ?,
|
||||
signature = ?,
|
||||
slot = ?,
|
||||
protocol_name = ?,
|
||||
program_id = ?,
|
||||
event_kind = ?,
|
||||
pool_account = ?,
|
||||
token_a_mint = ?,
|
||||
token_b_mint = ?,
|
||||
payload_json = ?,
|
||||
executed_at = ?
|
||||
WHERE id = ?
|
||||
"#,
|
||||
)
|
||||
.bind(dto.transaction_id)
|
||||
.bind(dto.dex_id)
|
||||
.bind(dto.pool_id)
|
||||
.bind(dto.pair_id)
|
||||
.bind(dto.signature.clone())
|
||||
.bind(slot_i64)
|
||||
.bind(dto.protocol_name.clone())
|
||||
.bind(dto.program_id.clone())
|
||||
.bind(dto.event_kind.clone())
|
||||
.bind(dto.pool_account.clone())
|
||||
.bind(dto.token_a_mint.clone())
|
||||
.bind(dto.token_b_mint.clone())
|
||||
.bind(dto.payload_json.clone())
|
||||
.bind(dto.executed_at.to_rfc3339())
|
||||
.bind(id)
|
||||
.execute(pool)
|
||||
.await;
|
||||
if let Err(error) = update_result {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot update k_sol_pool_lifecycle_events id '{}' on sqlite: {}",
|
||||
id, error
|
||||
)));
|
||||
}
|
||||
return Ok(id);
|
||||
}
|
||||
let insert_result = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO k_sol_pool_lifecycle_events (
|
||||
transaction_id,
|
||||
decoded_event_id,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
slot,
|
||||
protocol_name,
|
||||
program_id,
|
||||
event_kind,
|
||||
pool_account,
|
||||
token_a_mint,
|
||||
token_b_mint,
|
||||
payload_json,
|
||||
executed_at,
|
||||
created_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(dto.transaction_id)
|
||||
.bind(dto.decoded_event_id)
|
||||
.bind(dto.dex_id)
|
||||
.bind(dto.pool_id)
|
||||
.bind(dto.pair_id)
|
||||
.bind(dto.signature.clone())
|
||||
.bind(slot_i64)
|
||||
.bind(dto.protocol_name.clone())
|
||||
.bind(dto.program_id.clone())
|
||||
.bind(dto.event_kind.clone())
|
||||
.bind(dto.pool_account.clone())
|
||||
.bind(dto.token_a_mint.clone())
|
||||
.bind(dto.token_b_mint.clone())
|
||||
.bind(dto.payload_json.clone())
|
||||
.bind(dto.executed_at.to_rfc3339())
|
||||
.bind(dto.created_at.to_rfc3339())
|
||||
.execute(pool)
|
||||
.await;
|
||||
if let Err(error) = insert_result {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot insert k_sol_pool_lifecycle_events on sqlite: {}",
|
||||
error
|
||||
)));
|
||||
}
|
||||
let id_result = sqlx::query_scalar::<sqlx::Sqlite, i64>(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM k_sol_pool_lifecycle_events
|
||||
WHERE transaction_id = ?
|
||||
AND protocol_name = ?
|
||||
AND event_kind = ?
|
||||
AND signature = ?
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.bind(dto.transaction_id)
|
||||
.bind(dto.protocol_name.clone())
|
||||
.bind(dto.event_kind.clone())
|
||||
.bind(dto.signature.clone())
|
||||
.fetch_one(pool)
|
||||
.await;
|
||||
match id_result {
|
||||
Ok(id) => return Ok(id),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot fetch inserted k_sol_pool_lifecycle_events id for signature '{}' on sqlite: {}",
|
||||
dto.signature, error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Lists recent pool lifecycle events ordered from newest to oldest.
|
||||
pub async fn query_pool_lifecycle_events_list_recent(
|
||||
database: &crate::Database,
|
||||
limit: u32,
|
||||
) -> Result<std::vec::Vec<crate::PoolLifecycleEventDto>, crate::Error> {
|
||||
if limit == 0 {
|
||||
return Ok(std::vec::Vec::new());
|
||||
}
|
||||
match database.connection() {
|
||||
crate::DatabaseConnection::Sqlite(pool) => {
|
||||
let query_result = sqlx::query_as::<sqlx::Sqlite, crate::PoolLifecycleEventEntity>(
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
transaction_id,
|
||||
decoded_event_id,
|
||||
dex_id,
|
||||
pool_id,
|
||||
pair_id,
|
||||
signature,
|
||||
slot,
|
||||
protocol_name,
|
||||
program_id,
|
||||
event_kind,
|
||||
pool_account,
|
||||
token_a_mint,
|
||||
token_b_mint,
|
||||
payload_json,
|
||||
executed_at,
|
||||
created_at
|
||||
FROM k_sol_pool_lifecycle_events
|
||||
ORDER BY id DESC
|
||||
LIMIT ?
|
||||
"#,
|
||||
)
|
||||
.bind(i64::from(limit))
|
||||
.fetch_all(pool)
|
||||
.await;
|
||||
let entities = match query_result {
|
||||
Ok(entities) => entities,
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot list k_sol_pool_lifecycle_events on sqlite: {}",
|
||||
error
|
||||
)));
|
||||
},
|
||||
};
|
||||
let mut dtos = std::vec::Vec::new();
|
||||
for entity in entities {
|
||||
let dto_result = crate::PoolLifecycleEventDto::try_from(entity);
|
||||
let dto = match dto_result {
|
||||
Ok(dto) => dto,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
dtos.push(dto);
|
||||
}
|
||||
return Ok(dtos);
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1072,13 +1072,17 @@ async fn create_tbl_liquidity_events(pool: &sqlx::SqlitePool) -> Result<(), crat
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS k_sol_liquidity_events (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
transaction_id INTEGER NULL,
|
||||
decoded_event_id INTEGER NULL,
|
||||
dex_id INTEGER NOT NULL,
|
||||
pool_id INTEGER NOT NULL,
|
||||
pair_id INTEGER NULL,
|
||||
signature TEXT NOT NULL,
|
||||
instruction_index INTEGER NOT NULL,
|
||||
slot INTEGER NULL,
|
||||
program_id TEXT NULL,
|
||||
event_kind INTEGER NOT NULL,
|
||||
event_kind_text TEXT NULL,
|
||||
actor_wallet TEXT NULL,
|
||||
base_token_id INTEGER NOT NULL,
|
||||
quote_token_id INTEGER NOT NULL,
|
||||
@@ -1086,7 +1090,12 @@ CREATE TABLE IF NOT EXISTS k_sol_liquidity_events (
|
||||
base_amount TEXT NOT NULL,
|
||||
quote_amount TEXT NOT NULL,
|
||||
lp_amount TEXT NULL,
|
||||
amounts_are_complete INTEGER NOT NULL DEFAULT 1,
|
||||
payload_json TEXT NULL,
|
||||
executed_at TEXT NOT NULL,
|
||||
created_at TEXT NULL,
|
||||
FOREIGN KEY(transaction_id) REFERENCES k_sol_chain_transactions(id),
|
||||
FOREIGN KEY(decoded_event_id) REFERENCES k_sol_dex_decoded_events(id),
|
||||
FOREIGN KEY(dex_id) REFERENCES k_sol_dexes(id),
|
||||
FOREIGN KEY(pool_id) REFERENCES k_sol_pools(id),
|
||||
FOREIGN KEY(pair_id) REFERENCES k_sol_pairs(id),
|
||||
|
||||
@@ -9,6 +9,10 @@ pub enum LiquidityEventKind {
|
||||
Add,
|
||||
/// Liquidity removal.
|
||||
Remove,
|
||||
/// Concentrated-liquidity position opening without a guaranteed amount delta.
|
||||
PositionOpen,
|
||||
/// Concentrated-liquidity position closing without a guaranteed amount delta.
|
||||
PositionClose,
|
||||
}
|
||||
|
||||
impl LiquidityEventKind {
|
||||
@@ -17,6 +21,8 @@ impl LiquidityEventKind {
|
||||
match self {
|
||||
Self::Add => return 0,
|
||||
Self::Remove => return 1,
|
||||
Self::PositionOpen => return 2,
|
||||
Self::PositionClose => return 3,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +31,8 @@ impl LiquidityEventKind {
|
||||
match value {
|
||||
0 => return Ok(Self::Add),
|
||||
1 => return Ok(Self::Remove),
|
||||
2 => return Ok(Self::PositionOpen),
|
||||
3 => return Ok(Self::PositionClose),
|
||||
_ => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"invalid LiquidityEventKind value: {}",
|
||||
|
||||
Reference in New Issue
Block a user