From f2c227e08fa95f7b17ac335d4a6960597c67e5eb Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Tue, 5 May 2026 05:03:11 +0200 Subject: [PATCH] 0.7.25 --- CHANGELOG.md | 1 + Cargo.toml | 16 +- ROADMAP.md | 28 +- clippy.toml | 38 + kb_app/frontend/demo_pipeline2.html | 318 +++-- kb_app/frontend/ts/demo_pipeline2.ts | 93 ++ kb_app/src/demo_pipeline2.rs | 30 + kb_app/src/lib.rs | 1 + kb_lib/Cargo.toml | 2 + kb_lib/src/config.rs | 88 +- kb_lib/src/db.rs | 5 + kb_lib/src/db/connection.rs | 45 +- kb_lib/src/db/dtos/analysis_signal.rs | 12 +- kb_lib/src/db/dtos/chain_instruction.rs | 20 +- kb_lib/src/db/dtos/chain_slot.rs | 18 +- kb_lib/src/db/dtos/chain_transaction.rs | 16 +- kb_lib/src/db/dtos/db_metadata.rs | 14 +- kb_lib/src/db/dtos/db_runtime_event.rs | 10 +- kb_lib/src/db/dtos/dex.rs | 12 +- kb_lib/src/db/dtos/dex_decoded_event.rs | 10 +- kb_lib/src/db/dtos/known_http_endpoint.rs | 24 +- kb_lib/src/db/dtos/known_ws_endpoint.rs | 24 +- kb_lib/src/db/dtos/launch_attribution.rs | 12 +- kb_lib/src/db/dtos/launch_surface.rs | 12 +- kb_lib/src/db/dtos/launch_surface_key.rs | 12 +- kb_lib/src/db/dtos/liquidity_event.rs | 14 +- kb_lib/src/db/dtos/observed_token.rs | 24 +- kb_lib/src/db/dtos/onchain_observation.rs | 16 +- kb_lib/src/db/dtos/pair.rs | 12 +- kb_lib/src/db/dtos/pair_analytic_signal.rs | 14 +- kb_lib/src/db/dtos/pair_candle.rs | 12 +- kb_lib/src/db/dtos/pair_metric.rs | 12 +- kb_lib/src/db/dtos/pool.rs | 12 +- kb_lib/src/db/dtos/pool_listing.rs | 12 +- kb_lib/src/db/dtos/pool_origin.rs | 12 +- kb_lib/src/db/dtos/pool_token.rs | 12 +- kb_lib/src/db/dtos/swap.rs | 14 +- kb_lib/src/db/dtos/token.rs | 16 +- kb_lib/src/db/dtos/token_burn_event.rs | 18 +- kb_lib/src/db/dtos/token_mint_event.rs | 14 +- kb_lib/src/db/dtos/trade_event.rs | 18 +- kb_lib/src/db/dtos/wallet.rs | 12 +- kb_lib/src/db/dtos/wallet_holding.rs | 10 +- kb_lib/src/db/dtos/wallet_participation.rs | 17 +- kb_lib/src/db/queries.rs | 5 + kb_lib/src/db/queries/analysis_signal.rs | 14 +- kb_lib/src/db/queries/chain_instruction.rs | 24 +- kb_lib/src/db/queries/chain_slot.rs | 34 +- kb_lib/src/db/queries/chain_transaction.rs | 86 +- kb_lib/src/db/queries/db_metadata.rs | 40 +- kb_lib/src/db/queries/db_runtime_event.rs | 12 +- kb_lib/src/db/queries/dex.rs | 44 +- kb_lib/src/db/queries/dex_decoded_event.rs | 74 +- kb_lib/src/db/queries/known_http_endpoint.rs | 36 +- kb_lib/src/db/queries/known_ws_endpoint.rs | 37 +- kb_lib/src/db/queries/launch_attribution.rs | 54 +- kb_lib/src/db/queries/launch_surface.rs | 52 +- kb_lib/src/db/queries/launch_surface_key.rs | 56 +- kb_lib/src/db/queries/liquidity_event.rs | 24 +- kb_lib/src/db/queries/observed_token.rs | 36 +- kb_lib/src/db/queries/onchain_observation.rs | 18 +- kb_lib/src/db/queries/pair.rs | 90 +- kb_lib/src/db/queries/pair_analytic_signal.rs | 62 +- kb_lib/src/db/queries/pair_candle.rs | 28 +- kb_lib/src/db/queries/pair_metric.rs | 28 +- kb_lib/src/db/queries/pool.rs | 49 +- kb_lib/src/db/queries/pool_listing.rs | 40 +- kb_lib/src/db/queries/pool_origin.rs | 28 +- kb_lib/src/db/queries/pool_token.rs | 28 +- kb_lib/src/db/queries/swap.rs | 24 +- kb_lib/src/db/queries/token.rs | 237 +++- kb_lib/src/db/queries/token_burn_event.rs | 36 +- kb_lib/src/db/queries/token_mint_event.rs | 24 +- kb_lib/src/db/queries/trade_event.rs | 40 +- kb_lib/src/db/queries/wallet.rs | 28 +- kb_lib/src/db/queries/wallet_holding.rs | 28 +- kb_lib/src/db/queries/wallet_participation.rs | 34 +- kb_lib/src/db/schema.rs | 352 +++--- kb_lib/src/db/sqlite.rs | 27 +- .../src/db/types/analysis_signal_severity.rs | 34 +- kb_lib/src/db/types/liquidity_event_kind.rs | 18 +- .../src/db/types/observation_source_kind.rs | 30 +- kb_lib/src/db/types/observed_token_status.rs | 26 +- kb_lib/src/db/types/pool_kind.rs | 30 +- kb_lib/src/db/types/pool_status.rs | 25 +- kb_lib/src/db/types/pool_token_role.rs | 27 +- kb_lib/src/db/types/runtime_event_level.rs | 30 +- kb_lib/src/db/types/swap_trade_side.rs | 22 +- kb_lib/src/detect/service.rs | 56 +- kb_lib/src/detect/solana_ws.rs | 215 ++-- kb_lib/src/detect/types.rs | 16 +- kb_lib/src/detect/ws_relay.rs | 40 +- kb_lib/src/dex/dexlab.rs | 91 +- kb_lib/src/dex/fluxbeam.rs | 93 +- kb_lib/src/dex/meteora_damm_v1.rs | 97 +- kb_lib/src/dex/meteora_damm_v2.rs | 72 +- kb_lib/src/dex/meteora_dbc.rs | 95 +- kb_lib/src/dex/orca_whirlpools.rs | 138 +-- kb_lib/src/dex/pump_fun.rs | 38 +- kb_lib/src/dex/pump_swap.rs | 77 +- kb_lib/src/dex/raydium_amm_v4.rs | 24 +- kb_lib/src/dex/raydium_clmm.rs | 101 +- kb_lib/src/dex/raydium_cpmm.rs | 113 +- kb_lib/src/dex_decode.rs | 562 ++++----- kb_lib/src/dex_detect.rs | 749 ++++++------ kb_lib/src/error.rs | 40 +- kb_lib/src/http_client.rs | 497 ++++---- kb_lib/src/http_pool.rs | 156 +-- kb_lib/src/json_rpc_ws.rs | 92 +- kb_lib/src/launch_origin.rs | 94 +- kb_lib/src/lib.rs | 18 + kb_lib/src/local_pipeline_replay.rs | 244 ++++ kb_lib/src/pair_analytic_signal.rs | 110 +- kb_lib/src/pair_candle_aggregation.rs | 68 +- kb_lib/src/pair_candle_query.rs | 39 +- kb_lib/src/pair_symbol.rs | 294 +++++ kb_lib/src/pool_origin.rs | 30 +- kb_lib/src/solana_pubsub_ws.rs | 99 +- kb_lib/src/token_backfill.rs | 95 +- kb_lib/src/token_metadata.rs | 1024 +++++++++++++++++ kb_lib/src/tracing.rs | 113 +- kb_lib/src/trade_aggregation.rs | 215 ++-- kb_lib/src/tx_model.rs | 87 +- kb_lib/src/tx_resolution.rs | 61 +- kb_lib/src/wallet_holding_observation.rs | 54 +- kb_lib/src/wallet_observation.rs | 46 +- kb_lib/src/ws_client.rs | 618 ++++------ kb_lib/src/ws_hybrid_observation.rs | 73 +- kb_lib/src/ws_hybrid_runtime.rs | 23 +- kb_lib/src/ws_hybrid_watch.rs | 22 +- kb_lib/src/ws_manager.rs | 198 ++-- rustfmt.toml | 38 + 132 files changed, 5767 insertions(+), 4461 deletions(-) create mode 100644 clippy.toml create mode 100644 kb_lib/src/local_pipeline_replay.rs create mode 100644 kb_lib/src/pair_symbol.rs create mode 100644 kb_lib/src/token_metadata.rs create mode 100644 rustfmt.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9b263..309febe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,3 +55,4 @@ 0.7.22 - Ajout d’une première fenêtre `Demo Pipeline` dans `kb_app` pour l’inspection en lecture seule du pipeline `0.7.x`, avec recherche par signature, token mint, pair id ou pool address, affichage structuré des transactions résolues, événements DEX décodés, pools, paires, listings, launch origins, pool origins, wallets et holdings observés, trade events, pair metrics, candles et signaux analytiques déjà persistés, ainsi que conservation d’une instance partagée de la base SQLite pour éviter la réouverture et la réinitialisation du schéma à chaque commande UI 0.7.23 - Ajout du pilotage UI du backfill historique ciblé par `token mint` dans `kb_app`, avec saisie du rôle HTTP et des limites de signatures, affichage du résumé de backfill, réinspection automatique du token dans `Demo Pipeline` lorsque des objets persistés sont effectivement reconstruits, et gestion explicite du cas où le backfill réussit sans matérialiser de token exploitable dans la base locale 0.7.24 - Ajout de l’affichage graphique des candles / OHLCV dans `kb_app` via `echarts`, avec sélection de paire et de timeframe, rendu chandelier + volume, et prise en charge des candles matérialisées ou régénérées à la demande depuis `Demo Pipeline` +0.7.25 - En cours : préparation de l’enrichissement metadata des tokens, avec résolution locale limitée à SOL / WSOL, résolution des autres mints via comptes on-chain, Token-2022, Metaplex ou payloads DEX, et conservation explicite des cas non résolus diff --git a/Cargo.toml b/Cargo.toml index e71c0ba..749a6f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ ] [workspace.package] -version = "0.7.24" +version = "0.7.25" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot" @@ -70,3 +70,17 @@ lto = true # Enables link-time-optimizations. opt-level = 3 # s Prioritizes small binary size. Use `3` if you prefer speed. panic = "abort" # Higher performance by disabling panic handlers. strip = true # Ensures debug symbols are removed. + +[workspace.lints.clippy] +unwrap_used = "deny" +expect_used = "deny" +implicit_return = "deny" +needless_return = "allow" +useless_vec = "deny" +question_mark = "deny" +question_mark_used = "deny" +needless_match = "allow" +manual_ok_err = "allow" +manual_unwrap_or = "allow" +manual_map = "allow" +match_like_matches_macro = "allow" diff --git a/ROADMAP.md b/ROADMAP.md index 3d3fe10..45a4f8f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -696,19 +696,20 @@ Réalisé : - intégration du rendu graphique directement dans `Demo Pipeline`. ### 6.057. Version `0.7.25` — Enrichissement metadata des tokens -Objectif : rendre le catalogue local lisible et exploitable en associant les mints à des métadonnées minimales fiables. +Réalisé : -À faire : - -- ajouter une couche `token_metadata` dans `kb_lib`, distincte du décodage DEX et de l’UI, -- enrichir `kb_tokens` avec `symbol`, `name`, `decimals`, `metadata_uri`, `metadata_source`, `metadata_status` et `metadata_updated_at` lorsque le schéma le permet, -- ajouter une résolution locale des mints connus (`SOL`, `USDC`, `USDT`, `RAY`, `JitoSOL` et autres références stables), -- réutiliser les payloads déjà décodés des événements `pump_fun.create` / `pump_fun.create_v2_token` pour alimenter `name`, `symbol`, `uri` et `creator`, -- ajouter une résolution Metaplex Token Metadata PDA pour les tokens SPL classiques, -- ajouter une résolution Token-2022 via metadata pointer / extensions lorsque le mint utilise ce standard, -- stocker explicitement les cas non résolus afin d’éviter les tentatives répétées inutiles, -- exposer une commande UI ou un service de backfill permettant d’enrichir les tokens déjà présents en base, -- maintenir une politique de priorité claire entre sources : `known_mint`, `pump_fun_create`, `metaplex`, `token_2022`, puis `unresolved`. +- Ajout : + - Relecture locale du pipeline à partir des transactions brutes persistantes de la chaîne. + - Actualisation optionnelle des métadonnées de jetons manquantes lors de la relecture locale. + - Reconstruction des symboles de paires à partir des métadonnées des jetons. + - Commandes d'interface utilisateur dans le pipeline de démonstration 2 pour la relecture locale. + - Flux de travail d'actualisation du catalogue de jetons/paires piloté par les métadonnées. +- Modifications : + - Les symboles de paires sont désormais dérivés comme `BASE/QUOTE` lorsque les deux symboles de jetons sont disponibles. + - L'actualisation des métadonnées évite de nécessiter un remplissage complet de la blockchain lorsque les données de transaction brutes existent déjà localement. +- Corrections : + - Suppression des cycles complets de suppression/remplissage répétés pour les métadonnées et les entités locales dérivées. + - Conservation de l'accès SQL dans les modules de requêtes de base de données au lieu du SQL brut au niveau du service. ### 6.058. Version `0.7.26` — Validation multi-DEX et non-régression du pipeline Objectif : vérifier que les connecteurs déjà branchés restent cohérents avant d’ouvrir la phase d’analyse `0.8.x`. @@ -933,7 +934,7 @@ Le projet doit maintenir au minimum : La priorité immédiate est désormais la suivante : -1. ajouter l’enrichissement metadata des tokens afin que le catalogue affiche au minimum les symboles/noms connus et les métadonnées résolues, +1. ajouter l’enrichissement metadata des tokens afin que le catalogue affiche au minimum les symboles/noms résolus, sans hardcoder de mints hors SOL / WSOL, 2. rejouer une campagne de validation multi-DEX sur bases neuves pour `pump_fun`, `pump_swap`, `raydium_cpmm` et `raydium_clmm`, 3. constituer un corpus ciblé pour `raydium_amm_v4` legacy au lieu de s’appuyer sur des labels Raydium trop génériques, 4. conserver les événements non-candle enrichis en payload pour l’analyse future, sans créer de trades invalides, @@ -942,4 +943,3 @@ La priorité immédiate est désormais la suivante : 7. stabiliser l’ergonomie, les filtres et la navigation de l’UI d’inspection, 8. préparer ensuite l’ouverture de `0.8.x` pour l’analyse, les filtres, les patterns et les projections graphiques, 9. préparer enfin Yellowstone gRPC comme extension de capacité, et non comme remplacement du socle HTTP / WS existant. - diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..eefb5ca --- /dev/null +++ b/clippy.toml @@ -0,0 +1,38 @@ +# file: clippy.toml + +msrv = "1.85.0" + +# The project favors explicit control flow and visible intent. +# These settings complement the coding rules already enforced manually +# in code review: no `?`, no `unwrap`, no `expect`, explicit error paths. + +too-many-arguments-threshold = 16 +type-complexity-threshold = 250 +single-char-binding-names-threshold = 3 +trivial-copy-size-limit = 16 +pass-by-value-size-limit = 256 +stack-size-threshold = 512000 +vec-box-size-threshold = 4096 +max-fn-params-bools = 2 +max-include-file-size = 1048576 +cognitive-complexity-threshold = 25 +too-large-for-stack = 2048 +enum-variant-size-threshold = 200 +large-error-threshold = 128 +avoid-breaking-exported-api = true +allow-unwrap-in-tests = true +allow-expect-in-tests = true +allow-useless-vec-in-tests = true + +disallowed-macros = [] +disallowed-methods = [] +disallowed-names = ["foo", "bar", "baz", "tmp"] +disallowed-types = [] +allowed-idents-below-min-chars = [ + "id", + "tx", + "rx", + "ms", + "pcm", + "vad", +] diff --git a/kb_app/frontend/demo_pipeline2.html b/kb_app/frontend/demo_pipeline2.html index 0713202..1e19798 100644 --- a/kb_app/frontend/demo_pipeline2.html +++ b/kb_app/frontend/demo_pipeline2.html @@ -26,155 +26,229 @@
-
-
-

Catalogue local

-
- -
+ +
+
+
+ +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - +
+ + +
+
-
-
-
-

Backfill ciblé

- -
- - -
- -
- - -
- -
-
- - -
-
- - -
-
- -
- -
+ +
+
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+
+ + +
+
+ + +
+
-
- +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
-
-
-
-

Chargement candles

- -
- - -
- -
-
- - -
-
- - -
-
- -
- - -
- -
- + +
+
+

+ Rejoue le pipeline depuis les transactions déjà stockées en base sans refaire de getTransaction. +

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+ +
+

+ +

+
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ +
+
-
-
-

Backfill summary

- -
-
- -
-
-
-
-

Candles / OHLCV

-
- Aucun jeu de candles chargé. -
+
+
+

+ +

+
+
+
-
-
-
-
-
-

Log UI

- + +
+
+
+
+ Aucun jeu de candles chargé. +
+
+
+
+
+
+ +
+

+ +

+
+
+
+ +
+ +
-
diff --git a/kb_app/frontend/ts/demo_pipeline2.ts b/kb_app/frontend/ts/demo_pipeline2.ts index d078122..8abece3 100644 --- a/kb_app/frontend/ts/demo_pipeline2.ts +++ b/kb_app/frontend/ts/demo_pipeline2.ts @@ -38,6 +38,24 @@ interface PairCandle { updated_at: string; } + +interface KbLocalPipelineReplayResult { + selectedTransactionCount: number; + replayedTransactionCount: number; + decodeErrorCount: number; + detectErrorCount: number; + tradeAggregationErrorCount: number; + pairCandleErrorCount: number; + analyticSignalErrorCount: number; + decodedEventCount: number; + detectionCount: number; + tradeEventCount: number; + pairCandleCount: number; + analyticSignalCount: number; + tokenMetadataUpdatedCount: number; + pairSymbolUpdatedCount: number; + globalErrorCount: number; +} function appendLogLine(textarea: HTMLTextAreaElement, line: string): void { const now = new Date(); const timestamp = now.toLocaleTimeString("fr-CH", { hour12: false }); @@ -94,6 +112,25 @@ function readPositiveIntegerInput( return parsed; } + +function readOptionalPositiveIntegerInput( + input: HTMLInputElement, + logTextarea: HTMLTextAreaElement, + label: string, +): number | null | undefined { + const text = input.value.trim(); + if (text === "") { + return null; + } + + const parsed = Number.parseInt(text, 10); + if (Number.isNaN(parsed) || parsed <= 0) { + appendLogLine(logTextarea, `[ui] invalid ${label} '${text}'`); + return undefined; + } + + return parsed; +} function refreshPairSelect( catalog: KbDemoPipeline2CatalogPayload, select: HTMLSelectElement, @@ -308,6 +345,11 @@ document.addEventListener("DOMContentLoaded", async () => { const poolSignatureLimitInput = document.querySelector("#demoPipeline2PoolSignatureLimitInput"); const backfillPoolButton = document.querySelector("#demoPipeline2BackfillPoolButton"); + const replayLimitInput = document.querySelector("#demoPipeline2ReplayLimitInput"); + const replayMetadataCheckbox = document.querySelector("#demoPipeline2ReplayMetadataCheckbox"); + const replayMetadataLimitInput = document.querySelector("#demoPipeline2ReplayMetadataLimitInput"); + const replayLocalPipelineButton = document.querySelector("#demoPipeline2ReplayLocalPipelineButton"); + const pairSelect = document.querySelector("#demoPipeline2PairSelect"); const timeframeSelect = document.querySelector("#demoPipeline2TimeframeSelect"); const customTimeframeInput = document.querySelector("#demoPipeline2CustomTimeframeInput"); @@ -334,6 +376,10 @@ document.addEventListener("DOMContentLoaded", async () => { !poolInput || !poolSignatureLimitInput || !backfillPoolButton || + !replayLimitInput || + !replayMetadataCheckbox || + !replayMetadataLimitInput || + !replayLocalPipelineButton || !pairSelect || !timeframeSelect || !customTimeframeInput || @@ -497,6 +543,53 @@ document.addEventListener("DOMContentLoaded", async () => { } }); + replayLocalPipelineButton.addEventListener("click", async () => { + const replayLimit = readOptionalPositiveIntegerInput( + replayLimitInput, + logTextarea, + "replayLimit", + ); + if (replayLimit === undefined) { + return; + } + + const tokenMetadataLimit = readOptionalPositiveIntegerInput( + replayMetadataLimitInput, + logTextarea, + "tokenMetadataLimit", + ); + if (tokenMetadataLimit === undefined) { + return; + } + + appendLogLine( + logTextarea, + `[ui] launching local pipeline replay limit='${replayLimit ?? "none"}' metadata='${replayMetadataCheckbox.checked ? "yes" : "no"}'`, + ); + + try { + const result = await invoke( + "demo_pipeline2_replay_local_pipeline", + { + limit: replayLimit, + refreshMissingTokenMetadata: replayMetadataCheckbox.checked, + tokenMetadataLimit, + }, + ); + + backfillSummaryTextarea.value = JSON.stringify(result, null, 2); + + appendLogLine( + logTextarea, + `[ui] local pipeline replay completed: ${result.replayedTransactionCount.toString()} replayed, ${result.tradeEventCount.toString()} trades, ${result.pairCandleCount.toString()} candles`, + ); + + await refreshCatalog(); + } catch (error) { + appendLogLine(logTextarea, `[ui] local pipeline replay error: ${String(error)}`); + } + }); + loadCandlesButton.addEventListener("click", async () => { const pairIdText = pairSelect.value.trim(); if (pairIdText === "") { diff --git a/kb_app/src/demo_pipeline2.rs b/kb_app/src/demo_pipeline2.rs index 7550ac5..20df13a 100644 --- a/kb_app/src/demo_pipeline2.rs +++ b/kb_app/src/demo_pipeline2.rs @@ -507,6 +507,36 @@ async fn kb_demo_pipeline2_build_catalog( }) } +/// Replays the local pipeline from persisted raw transactions. +#[tauri::command] +pub(crate) async fn demo_pipeline2_replay_local_pipeline( + state: tauri::State<'_, crate::KbAppState>, + limit: std::option::Option, + refresh_missing_token_metadata: bool, + token_metadata_limit: std::option::Option, +) -> Result { + let config = kb_lib::KbLocalPipelineReplayConfig { + limit, + refresh_missing_token_metadata, + token_metadata_limit, + }; + let database = state.database.clone(); + let service = if refresh_missing_token_metadata { + kb_lib::KbLocalPipelineReplayService::new_with_http_pool( + std::sync::Arc::new(state.http_pool.clone()), + database, + "history_backfill".to_string(), + ) + } else { + kb_lib::KbLocalPipelineReplayService::new(database) + }; + let replay_result = service.replay_local_pipeline(&config).await; + match replay_result { + Ok(result) => Ok(result), + Err(error) => Err(format!("local pipeline replay failed: {}", error)), + } +} + fn kb_demo_pipeline2_normalize_http_role( role: std::option::Option, ) -> std::string::String { diff --git a/kb_app/src/lib.rs b/kb_app/src/lib.rs index 76e9724..c6167d9 100644 --- a/kb_app/src/lib.rs +++ b/kb_app/src/lib.rs @@ -150,6 +150,7 @@ pub async fn run() -> Result<(), kb_lib::KbError> { crate::demo_pipeline2::demo_pipeline2_backfill_token_mint, crate::demo_pipeline2::demo_pipeline2_backfill_pool_address, crate::demo_pipeline2::demo_pipeline2_get_pair_candles, + crate::demo_pipeline2::demo_pipeline2_replay_local_pipeline, ]); tauri_builder = tauri_builder.plugin(tracing_builder.build::()); tauri_builder = tauri_builder.setup(|app| { diff --git a/kb_lib/Cargo.toml b/kb_lib/Cargo.toml index 88ff73b..62976f8 100644 --- a/kb_lib/Cargo.toml +++ b/kb_lib/Cargo.toml @@ -31,3 +31,5 @@ tracing-subscriber.workspace = true [dev-dependencies] tempfile.workspace = true +[lints] +workspace = true diff --git a/kb_lib/src/config.rs b/kb_lib/src/config.rs index c6678ff..1c1f55a 100644 --- a/kb_lib/src/config.rs +++ b/kb_lib/src/config.rs @@ -20,7 +20,7 @@ pub struct KbConfig { impl KbConfig { /// Returns the default path of the JSON configuration file. pub fn default_path() -> std::path::PathBuf { - kb_workspace_root_dir().join("config.json") + return kb_workspace_root_dir().join("config.json"); } /// Loads a configuration from a JSON file and validates it. @@ -34,7 +34,7 @@ impl KbConfig { "cannot read configuration file '{}': {error}", path_ref.display() ))); - } + }, }; let config_result = serde_json::from_str::(&content); let config = match config_result { @@ -44,36 +44,28 @@ impl KbConfig { "cannot parse configuration file '{}': {error}", path_ref.display() ))); - } + }, }; let validation_result = config.validate(); match validation_result { - Ok(()) => Ok(config), - Err(error) => Err(error), + Ok(()) => return Ok(config), + Err(error) => return Err(error), } } /// Validates the current configuration. pub fn validate(&self) -> Result<(), crate::KbError> { if self.app.name.trim().is_empty() { - return Err(crate::KbError::Config( - "app.name must not be empty".to_string(), - )); + return Err(crate::KbError::Config("app.name must not be empty".to_string())); } if self.app.environment.trim().is_empty() { - return Err(crate::KbError::Config( - "app.environment must not be empty".to_string(), - )); + return Err(crate::KbError::Config("app.environment must not be empty".to_string())); } if self.logging.level.trim().is_empty() { - return Err(crate::KbError::Config( - "logging.level must not be empty".to_string(), - )); + return Err(crate::KbError::Config("logging.level must not be empty".to_string())); } if self.logging.directory.trim().is_empty() { - return Err(crate::KbError::Config( - "logging.directory must not be empty".to_string(), - )); + return Err(crate::KbError::Config("logging.directory must not be empty".to_string())); } if self.logging.file_prefix.trim().is_empty() { return Err(crate::KbError::Config( @@ -81,9 +73,7 @@ impl KbConfig { )); } if self.data.sqlite_path.trim().is_empty() { - return Err(crate::KbError::Config( - "data.sqlite_path must not be empty".to_string(), - )); + return Err(crate::KbError::Config("data.sqlite_path must not be empty".to_string())); } if self.data.wallets_directory.trim().is_empty() { return Err(crate::KbError::Config( @@ -131,7 +121,7 @@ impl KbConfig { return Err(error); } } - Ok(()) + return Ok(()); } /// Creates the basic runtime directories required by the current configuration. @@ -165,7 +155,7 @@ impl KbConfig { } } } - Ok(()) + return Ok(()); } /// Finds one HTTP endpoint by its logical name. @@ -173,10 +163,11 @@ impl KbConfig { &self, endpoint_name: &str, ) -> std::option::Option<&KbHttpEndpointConfig> { - self.solana + return self + .solana .http_endpoints .iter() - .find(|endpoint| endpoint.name == endpoint_name) + .find(|endpoint| return endpoint.name == endpoint_name); } /// Returns a named WebSocket endpoint by reference. @@ -184,10 +175,11 @@ impl KbConfig { &self, endpoint_name: &str, ) -> std::option::Option<&KbWsEndpointConfig> { - self.solana + return self + .solana .ws_endpoints .iter() - .find(|endpoint| endpoint.name == endpoint_name) + .find(|endpoint| return endpoint.name == endpoint_name); } fn validate_http_endpoint( @@ -196,11 +188,9 @@ impl KbConfig { endpoint_names: &mut std::vec::Vec, ) -> Result<(), crate::KbError> { if endpoint.name.trim().is_empty() { - return Err(crate::KbError::Config( - "http endpoint name must not be empty".to_string(), - )); + return Err(crate::KbError::Config("http endpoint name must not be empty".to_string())); } - if endpoint_names.iter().any(|name| name == &endpoint.name) { + if endpoint_names.iter().any(|name| return name == &endpoint.name) { return Err(crate::KbError::Config(format!( "duplicated endpoint name '{}'", endpoint.name @@ -237,7 +227,7 @@ impl KbConfig { ))); } endpoint_names.push(endpoint.name.clone()); - Ok(()) + return Ok(()); } fn validate_ws_endpoint( @@ -246,11 +236,9 @@ impl KbConfig { endpoint_names: &mut std::vec::Vec, ) -> Result<(), crate::KbError> { if endpoint.name.trim().is_empty() { - return Err(crate::KbError::Config( - "ws endpoint name must not be empty".to_string(), - )); + return Err(crate::KbError::Config("ws endpoint name must not be empty".to_string())); } - if endpoint_names.iter().any(|name| name == &endpoint.name) { + if endpoint_names.iter().any(|name| return name == &endpoint.name) { return Err(crate::KbError::Config(format!( "duplicated endpoint name '{}'", endpoint.name @@ -299,7 +287,7 @@ impl KbConfig { ))); } endpoint_names.push(endpoint.name.clone()); - Ok(()) + return Ok(()); } } @@ -350,7 +338,7 @@ pub struct KbLoggingConfig { impl KbLoggingConfig { /// Returns the resolved logging directory path. pub fn directory_path(&self) -> std::path::PathBuf { - kb_resolve_workspace_relative_path(&self.directory) + return kb_resolve_workspace_relative_path(&self.directory); } } @@ -366,12 +354,12 @@ pub struct KbDataConfig { impl KbDataConfig { /// Returns the resolved SQLite database path. pub fn sqlite_path_buf(&self) -> std::path::PathBuf { - kb_resolve_workspace_relative_path(&self.sqlite_path) + return kb_resolve_workspace_relative_path(&self.sqlite_path); } /// Returns the resolved wallets directory path. pub fn wallets_directory_path(&self) -> std::path::PathBuf { - kb_resolve_workspace_relative_path(&self.wallets_directory) + return kb_resolve_workspace_relative_path(&self.wallets_directory); } } @@ -433,7 +421,7 @@ impl KbHttpEndpointConfig { Some(env_var_name) => env_var_name, None => { return Ok(self.url.clone()); - } + }, }; let api_key_result = std::env::var(env_var_name); let api_key = match api_key_result { @@ -443,13 +431,13 @@ impl KbHttpEndpointConfig { "cannot resolve api key env var '{}' for http endpoint '{}': {}", env_var_name, self.name, error ))); - } + }, }; let placeholder = format!("${{{}}}", env_var_name); if self.url.contains(&placeholder) { return Ok(self.url.replace(&placeholder, &api_key)); } - Ok(self.url.clone()) + return Ok(self.url.clone()); } } @@ -487,7 +475,7 @@ pub struct KbWsEndpointConfig { impl KbWsEndpointConfig { /// Returns the resolved endpoint URL. pub fn resolved_url(&self) -> Result { - kb_resolve_endpoint_url(&self.url, &self.api_key_env_var) + return kb_resolve_endpoint_url(&self.url, &self.api_key_env_var); } } @@ -512,7 +500,7 @@ pub struct KbSqliteDatabaseConfig { impl KbSqliteDatabaseConfig { /// Returns the resolved SQLite database path. pub fn path_buf(&self) -> std::path::PathBuf { - kb_resolve_workspace_relative_path(&self.path) + return kb_resolve_workspace_relative_path(&self.path); } } @@ -531,8 +519,8 @@ pub struct KbDatabaseConfig { fn kb_workspace_root_dir() -> std::path::PathBuf { let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); match manifest_dir.parent() { - Some(parent) => parent.to_path_buf(), - None => manifest_dir, + Some(parent) => return parent.to_path_buf(), + None => return manifest_dir, } } @@ -541,7 +529,7 @@ fn kb_resolve_workspace_relative_path>(path: P) -> std if input_path.is_absolute() { return input_path; } - kb_workspace_root_dir().join(input_path) + return kb_workspace_root_dir().join(input_path); } fn kb_resolve_endpoint_url( @@ -553,7 +541,7 @@ fn kb_resolve_endpoint_url( Some(env_var_name) => env_var_name, None => { return Ok(url.to_string()); - } + }, }; let placeholder = format!("${{{env_var_name}}}"); if !url.contains(&placeholder) { @@ -567,7 +555,7 @@ fn kb_resolve_endpoint_url( "environment variable '{}' is required to resolve endpoint url '{}': {error}", env_var_name, url ))); - } + }, }; - Ok(url.replace(&placeholder, &env_value)) + return Ok(url.replace(&placeholder, &env_value)); } diff --git a/kb_lib/src/db.rs b/kb_lib/src/db.rs index a18a418..9281913 100644 --- a/kb_lib/src/db.rs +++ b/kb_lib/src/db.rs @@ -87,6 +87,7 @@ pub use queries::get_dex_by_code; pub use queries::get_dex_decoded_event_by_key; pub use queries::get_known_http_endpoint; pub use queries::get_known_ws_endpoint; +pub use queries::get_latest_pump_fun_create_payload_by_mint; pub use queries::get_launch_attribution_by_decoded_event_id; pub use queries::get_launch_surface_by_code; pub use queries::get_launch_surface_key_by_match; @@ -98,6 +99,7 @@ pub use queries::get_pair_metric_by_pair_id; pub use queries::get_pool_by_address; pub use queries::get_pool_listing_by_pool_id; pub use queries::get_pool_origin_by_pool_id; +pub use queries::get_token_by_id; pub use queries::get_token_by_mint; pub use queries::get_trade_event_by_decoded_event_id; pub use queries::get_wallet_by_address; @@ -108,6 +110,7 @@ pub use queries::insert_chain_instruction; pub use queries::insert_db_runtime_event; pub use queries::insert_onchain_observation; pub use queries::list_chain_instructions_by_transaction_id; +pub use queries::list_chain_transaction_signatures_for_replay; pub use queries::list_db_metadata; pub use queries::list_dex_decoded_events_by_transaction_id; pub use queries::list_dexes; @@ -135,12 +138,14 @@ pub use queries::list_recent_swaps; pub use queries::list_recent_token_burn_events; pub use queries::list_recent_token_mint_events; pub use queries::list_tokens; +pub use queries::list_tokens_missing_metadata; pub use queries::list_trade_events_by_pair_id; pub use queries::list_trade_events_by_transaction_id; pub use queries::list_wallet_holdings_by_wallet_id; pub use queries::list_wallet_participations_by_pool_id; pub use queries::list_wallet_participations_by_wallet_id; pub use queries::list_wallets; +pub use queries::update_pair_symbol; pub use queries::upsert_chain_slot; pub use queries::upsert_chain_transaction; pub use queries::upsert_db_metadata; diff --git a/kb_lib/src/db/connection.rs b/kb_lib/src/db/connection.rs index 2092e04..989efcf 100644 --- a/kb_lib/src/db/connection.rs +++ b/kb_lib/src/db/connection.rs @@ -19,9 +19,7 @@ pub struct KbDatabase { impl KbDatabase { /// Opens a database connection without initializing the schema. - pub async fn connect( - config: &crate::KbDatabaseConfig, - ) -> Result { + pub async fn connect(config: &crate::KbDatabaseConfig) -> Result { if !config.enabled { return Err(crate::KbError::Config( "database is disabled in configuration".to_string(), @@ -40,11 +38,11 @@ impl KbDatabase { Ok(pool) => pool, Err(error) => return Err(error), }; - Ok(Self { + return Ok(Self { backend: crate::KbDatabaseBackend::Sqlite, database_url, connection: KbDatabaseConnection::Sqlite(pool), - }) + }); }, } } @@ -64,47 +62,40 @@ impl KbDatabase { return Err(error); } } - Ok(database) + return Ok(database); } /// Returns the configured backend. - pub fn backend( - &self, - ) -> crate::KbDatabaseBackend { - self.backend + pub fn backend(&self) -> crate::KbDatabaseBackend { + return self.backend; } /// Returns a displayable database URL-like string. - pub fn database_url( - &self, - ) -> &str { - &self.database_url + pub fn database_url(&self) -> &str { + return &self.database_url; } /// Pings the database. - pub async fn ping( - &self, - ) -> Result<(), crate::KbError> { + pub async fn ping(&self) -> Result<(), crate::KbError> { match &self.connection { KbDatabaseConnection::Sqlite(pool) => { let ping_result = sqlx::query("SELECT 1").execute(pool).await; match ping_result { - Ok(_) => Ok(()), - Err(error) => Err(crate::KbError::Db(format!( - "cannot ping sqlite database '{}': {}", - self.database_url, - error - ))), + Ok(_) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot ping sqlite database '{}': {}", + self.database_url, error + ))); + }, } }, } } /// Returns the underlying connection enum. - pub(crate) fn connection( - &self, - ) -> &KbDatabaseConnection { - &self.connection + pub(crate) fn connection(&self) -> &KbDatabaseConnection { + return &self.connection; } } diff --git a/kb_lib/src/db/dtos/analysis_signal.rs b/kb_lib/src/db/dtos/analysis_signal.rs index bb0f8e1..35b6b79 100644 --- a/kb_lib/src/db/dtos/analysis_signal.rs +++ b/kb_lib/src/db/dtos/analysis_signal.rs @@ -33,7 +33,7 @@ impl KbAnalysisSignalDto { score: std::option::Option, payload: serde_json::Value, ) -> Self { - Self { + return Self { id: None, signal_kind, severity, @@ -42,7 +42,7 @@ impl KbAnalysisSignalDto { score, payload, created_at: chrono::Utc::now(), - } + }; } } @@ -63,7 +63,7 @@ impl TryFrom for KbAnalysisSignalDto { "cannot parse analysis signal created_at '{}': {}", entity.created_at, error ))); - } + }, }; let payload_result = serde_json::from_str::(&entity.payload_json); let payload = match payload_result { @@ -73,9 +73,9 @@ impl TryFrom for KbAnalysisSignalDto { "cannot parse analysis signal payload_json '{}': {}", entity.payload_json, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), signal_kind: entity.signal_kind, severity, @@ -84,6 +84,6 @@ impl TryFrom for KbAnalysisSignalDto { score: entity.score, payload, created_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/chain_instruction.rs b/kb_lib/src/db/dtos/chain_instruction.rs index f0cdbc4..f86fa94 100644 --- a/kb_lib/src/db/dtos/chain_instruction.rs +++ b/kb_lib/src/db/dtos/chain_instruction.rs @@ -49,7 +49,7 @@ impl KbChainInstructionDto { parsed_type: std::option::Option, parsed_json: std::option::Option, ) -> Self { - Self { + return Self { id: None, transaction_id, parent_instruction_id, @@ -63,7 +63,7 @@ impl KbChainInstructionDto { parsed_type, parsed_json, created_at: chrono::Utc::now(), - } + }; } } @@ -79,7 +79,7 @@ impl TryFrom for KbChainInstructionDto { "cannot convert chain instruction instruction_index '{}' to u32: {}", entity.instruction_index, error ))); - } + }, }; let inner_instruction_index = match entity.inner_instruction_index { Some(inner_instruction_index) => { @@ -91,9 +91,9 @@ impl TryFrom for KbChainInstructionDto { "cannot convert chain instruction inner_instruction_index '{}' to u32: {}", inner_instruction_index, error ))); - } + }, } - } + }, None => None, }; let stack_height = match entity.stack_height { @@ -106,9 +106,9 @@ impl TryFrom for KbChainInstructionDto { "cannot convert chain instruction stack_height '{}' to u32: {}", stack_height, error ))); - } + }, } - } + }, None => None, }; let created_at_result = chrono::DateTime::parse_from_rfc3339(&entity.created_at); @@ -119,9 +119,9 @@ impl TryFrom for KbChainInstructionDto { "cannot parse chain instruction created_at '{}': {}", entity.created_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), transaction_id: entity.transaction_id, parent_instruction_id: entity.parent_instruction_id, @@ -135,6 +135,6 @@ impl TryFrom for KbChainInstructionDto { parsed_type: entity.parsed_type, parsed_json: entity.parsed_json, created_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/chain_slot.rs b/kb_lib/src/db/dtos/chain_slot.rs index e8bf863..eae6ce0 100644 --- a/kb_lib/src/db/dtos/chain_slot.rs +++ b/kb_lib/src/db/dtos/chain_slot.rs @@ -25,13 +25,13 @@ impl KbChainSlotDto { block_time_unix: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { slot, parent_slot, block_time_unix, created_at: now, updated_at: now, - } + }; } } @@ -47,7 +47,7 @@ impl TryFrom for KbChainSlotDto { "cannot convert chain slot '{}' to u64: {}", entity.slot, error ))); - } + }, }; let parent_slot = match entity.parent_slot { Some(parent_slot) => { @@ -59,9 +59,9 @@ impl TryFrom for KbChainSlotDto { "cannot convert chain parent_slot '{}' to u64: {}", parent_slot, error ))); - } + }, } - } + }, None => None, }; let created_at_result = chrono::DateTime::parse_from_rfc3339(&entity.created_at); @@ -72,7 +72,7 @@ impl TryFrom for KbChainSlotDto { "cannot parse chain slot created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -82,14 +82,14 @@ impl TryFrom for KbChainSlotDto { "cannot parse chain slot updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { slot, parent_slot, block_time_unix: entity.block_time_unix, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/chain_transaction.rs b/kb_lib/src/db/dtos/chain_transaction.rs index 8152927..fe05a1b 100644 --- a/kb_lib/src/db/dtos/chain_transaction.rs +++ b/kb_lib/src/db/dtos/chain_transaction.rs @@ -43,7 +43,7 @@ impl KbChainTransactionDto { transaction_json: std::string::String, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, signature, slot, @@ -55,7 +55,7 @@ impl KbChainTransactionDto { transaction_json, created_at: now, updated_at: now, - } + }; } } @@ -73,9 +73,9 @@ impl TryFrom for KbChainTransactionDto { "cannot convert chain transaction slot '{}' to u64: {}", slot, error ))); - } + }, } - } + }, None => None, }; let created_at_result = chrono::DateTime::parse_from_rfc3339(&entity.created_at); @@ -86,7 +86,7 @@ impl TryFrom for KbChainTransactionDto { "cannot parse chain transaction created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -96,9 +96,9 @@ impl TryFrom for KbChainTransactionDto { "cannot parse chain transaction updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), signature: entity.signature, slot, @@ -110,6 +110,6 @@ impl TryFrom for KbChainTransactionDto { transaction_json: entity.transaction_json, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/db_metadata.rs b/kb_lib/src/db/dtos/db_metadata.rs index 2416ca5..7ceb060 100644 --- a/kb_lib/src/db/dtos/db_metadata.rs +++ b/kb_lib/src/db/dtos/db_metadata.rs @@ -16,11 +16,11 @@ pub struct KbDbMetadataDto { impl KbDbMetadataDto { /// Creates a new metadata DTO with the current UTC timestamp. pub fn new(key: std::string::String, value: std::string::String) -> Self { - Self { + return Self { key, value, updated_at: chrono::Utc::now(), - } + }; } } @@ -36,22 +36,22 @@ impl TryFrom for KbDbMetadataDto { "cannot parse db metadata timestamp '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { key: entity.key, value: entity.value, updated_at: parsed.with_timezone(&chrono::Utc), - }) + }); } } impl From for crate::KbDbMetadataEntity { fn from(dto: KbDbMetadataDto) -> Self { - Self { + return Self { key: dto.key, value: dto.value, updated_at: dto.updated_at.to_rfc3339(), - } + }; } } diff --git a/kb_lib/src/db/dtos/db_runtime_event.rs b/kb_lib/src/db/dtos/db_runtime_event.rs index a82f3d0..d28777b 100644 --- a/kb_lib/src/db/dtos/db_runtime_event.rs +++ b/kb_lib/src/db/dtos/db_runtime_event.rs @@ -27,14 +27,14 @@ impl KbDbRuntimeEventDto { source: std::string::String, message: std::string::String, ) -> Self { - Self { + return Self { id: None, event_kind, level, source, message, created_at: chrono::Utc::now(), - } + }; } } @@ -50,20 +50,20 @@ impl TryFrom for KbDbRuntimeEventDto { "cannot parse runtime event created_at '{}': {}", entity.created_at, error ))); - } + }, }; let level_result = crate::KbDbRuntimeEventLevel::from_i16(entity.level); let level = match level_result { Ok(level) => level, Err(error) => return Err(error), }; - Ok(Self { + return Ok(Self { id: Some(entity.id), event_kind: entity.event_kind, level, source: entity.source, message: entity.message, created_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/dex.rs b/kb_lib/src/db/dtos/dex.rs index 1aa2cb4..7b7f259 100644 --- a/kb_lib/src/db/dtos/dex.rs +++ b/kb_lib/src/db/dtos/dex.rs @@ -33,7 +33,7 @@ impl KbDexDto { is_enabled: bool, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, code, name, @@ -42,7 +42,7 @@ impl KbDexDto { is_enabled, created_at: now, updated_at: now, - } + }; } } @@ -58,7 +58,7 @@ impl TryFrom for KbDexDto { "cannot parse dex created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -68,9 +68,9 @@ impl TryFrom for KbDexDto { "cannot parse dex updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), code: entity.code, name: entity.name, @@ -79,6 +79,6 @@ impl TryFrom for KbDexDto { is_enabled: entity.is_enabled != 0, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/dex_decoded_event.rs b/kb_lib/src/db/dtos/dex_decoded_event.rs index 48a0b69..e877e52 100644 --- a/kb_lib/src/db/dtos/dex_decoded_event.rs +++ b/kb_lib/src/db/dtos/dex_decoded_event.rs @@ -49,7 +49,7 @@ impl KbDexDecodedEventDto { market_account: std::option::Option, payload_json: std::string::String, ) -> Self { - Self { + return Self { id: None, transaction_id, instruction_id, @@ -63,7 +63,7 @@ impl KbDexDecodedEventDto { market_account, payload_json, created_at: chrono::Utc::now(), - } + }; } } @@ -79,9 +79,9 @@ impl TryFrom for KbDexDecodedEventDto { "cannot parse dex decoded event created_at '{}': {}", entity.created_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), transaction_id: entity.transaction_id, instruction_id: entity.instruction_id, @@ -95,6 +95,6 @@ impl TryFrom for KbDexDecodedEventDto { market_account: entity.market_account, payload_json: entity.payload_json, created_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/known_http_endpoint.rs b/kb_lib/src/db/dtos/known_http_endpoint.rs index ff0d9ac..029849e 100644 --- a/kb_lib/src/db/dtos/known_http_endpoint.rs +++ b/kb_lib/src/db/dtos/known_http_endpoint.rs @@ -30,7 +30,7 @@ impl KbKnownHttpEndpointDto { enabled: bool, roles: std::vec::Vec, ) -> Self { - Self { + return Self { name, provider, url, @@ -38,7 +38,7 @@ impl KbKnownHttpEndpointDto { roles, last_seen_at: None, updated_at: chrono::Utc::now(), - } + }; } } @@ -55,7 +55,7 @@ impl TryFrom for KbKnownHttpEndpointDto { "cannot parse known http endpoint roles_json '{}': {}", entity.roles_json, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -65,7 +65,7 @@ impl TryFrom for KbKnownHttpEndpointDto { "cannot parse known http endpoint updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; let last_seen_at = match entity.last_seen_at { Some(last_seen_at_text) => { @@ -77,12 +77,12 @@ impl TryFrom for KbKnownHttpEndpointDto { "cannot parse known http endpoint last_seen_at '{}': {}", last_seen_at_text, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { name: entity.name, provider: entity.provider, url: entity.url, @@ -90,7 +90,7 @@ impl TryFrom for KbKnownHttpEndpointDto { roles, last_seen_at, updated_at, - }) + }); } } @@ -106,16 +106,16 @@ impl TryFrom for crate::KbKnownHttpEndpointEntity { "cannot serialize known http endpoint roles: {}", error ))); - } + }, }; - Ok(Self { + return Ok(Self { name: dto.name, provider: dto.provider, url: dto.url, enabled: if dto.enabled { 1 } else { 0 }, roles_json, - last_seen_at: dto.last_seen_at.map(|value| value.to_rfc3339()), + last_seen_at: dto.last_seen_at.map(|value| return value.to_rfc3339()), updated_at: dto.updated_at.to_rfc3339(), - }) + }); } } diff --git a/kb_lib/src/db/dtos/known_ws_endpoint.rs b/kb_lib/src/db/dtos/known_ws_endpoint.rs index 8820af3..96d1426 100644 --- a/kb_lib/src/db/dtos/known_ws_endpoint.rs +++ b/kb_lib/src/db/dtos/known_ws_endpoint.rs @@ -30,7 +30,7 @@ impl KbKnownWsEndpointDto { enabled: bool, roles: std::vec::Vec, ) -> Self { - Self { + return Self { name, provider, url, @@ -38,7 +38,7 @@ impl KbKnownWsEndpointDto { roles, last_seen_at: None, updated_at: chrono::Utc::now(), - } + }; } } @@ -55,7 +55,7 @@ impl TryFrom for KbKnownWsEndpointDto { "cannot parse known ws endpoint roles_json '{}': {}", entity.roles_json, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -65,7 +65,7 @@ impl TryFrom for KbKnownWsEndpointDto { "cannot parse known ws endpoint updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; let last_seen_at = match entity.last_seen_at { Some(last_seen_at_text) => { @@ -77,12 +77,12 @@ impl TryFrom for KbKnownWsEndpointDto { "cannot parse known ws endpoint last_seen_at '{}': {}", last_seen_at_text, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { name: entity.name, provider: entity.provider, url: entity.url, @@ -90,7 +90,7 @@ impl TryFrom for KbKnownWsEndpointDto { roles, last_seen_at, updated_at, - }) + }); } } @@ -106,16 +106,16 @@ impl TryFrom for crate::KbKnownWsEndpointEntity { "cannot serialize known ws endpoint roles: {}", error ))); - } + }, }; - Ok(Self { + return Ok(Self { name: dto.name, provider: dto.provider, url: dto.url, enabled: if dto.enabled { 1 } else { 0 }, roles_json, - last_seen_at: dto.last_seen_at.map(|value| value.to_rfc3339()), + last_seen_at: dto.last_seen_at.map(|value| return value.to_rfc3339()), updated_at: dto.updated_at.to_rfc3339(), - }) + }); } } diff --git a/kb_lib/src/db/dtos/launch_attribution.rs b/kb_lib/src/db/dtos/launch_attribution.rs index 2c57f47..bf862e1 100644 --- a/kb_lib/src/db/dtos/launch_attribution.rs +++ b/kb_lib/src/db/dtos/launch_attribution.rs @@ -45,7 +45,7 @@ impl KbLaunchAttributionDto { matched_value: std::string::String, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, launch_surface_id, transaction_id, @@ -58,7 +58,7 @@ impl KbLaunchAttributionDto { matched_value, attributed_at: now, updated_at: now, - } + }; } } @@ -74,7 +74,7 @@ impl TryFrom for KbLaunchAttributionDto { "cannot parse launch_attribution attributed_at '{}': {}", entity.attributed_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -84,9 +84,9 @@ impl TryFrom for KbLaunchAttributionDto { "cannot parse launch_attribution updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), launch_surface_id: entity.launch_surface_id, transaction_id: entity.transaction_id, @@ -99,6 +99,6 @@ impl TryFrom for KbLaunchAttributionDto { matched_value: entity.matched_value, attributed_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/launch_surface.rs b/kb_lib/src/db/dtos/launch_surface.rs index ab782bb..dda5b21 100644 --- a/kb_lib/src/db/dtos/launch_surface.rs +++ b/kb_lib/src/db/dtos/launch_surface.rs @@ -30,7 +30,7 @@ impl KbLaunchSurfaceDto { is_enabled: bool, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, code, name, @@ -38,7 +38,7 @@ impl KbLaunchSurfaceDto { is_enabled, created_at: now, updated_at: now, - } + }; } } @@ -54,7 +54,7 @@ impl TryFrom for KbLaunchSurfaceDto { "cannot parse launch_surface created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -64,9 +64,9 @@ impl TryFrom for KbLaunchSurfaceDto { "cannot parse launch_surface updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), code: entity.code, name: entity.name, @@ -74,6 +74,6 @@ impl TryFrom for KbLaunchSurfaceDto { is_enabled: entity.is_enabled != 0, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/launch_surface_key.rs b/kb_lib/src/db/dtos/launch_surface_key.rs index 1aef978..c6ba7de 100644 --- a/kb_lib/src/db/dtos/launch_surface_key.rs +++ b/kb_lib/src/db/dtos/launch_surface_key.rs @@ -27,14 +27,14 @@ impl KbLaunchSurfaceKeyDto { match_value: std::string::String, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, launch_surface_id, match_kind, match_value, created_at: now, updated_at: now, - } + }; } } @@ -50,7 +50,7 @@ impl TryFrom for KbLaunchSurfaceKeyDto { "cannot parse launch_surface_key created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -60,15 +60,15 @@ impl TryFrom for KbLaunchSurfaceKeyDto { "cannot parse launch_surface_key updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), launch_surface_id: entity.launch_surface_id, match_kind: entity.match_kind, match_value: entity.match_value, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/liquidity_event.rs b/kb_lib/src/db/dtos/liquidity_event.rs index 4b1929f..e655462 100644 --- a/kb_lib/src/db/dtos/liquidity_event.rs +++ b/kb_lib/src/db/dtos/liquidity_event.rs @@ -57,7 +57,7 @@ impl KbLiquidityEventDto { quote_amount: std::string::String, lp_amount: std::option::Option, ) -> Self { - Self { + return Self { id: None, dex_id, pool_id, @@ -74,7 +74,7 @@ impl KbLiquidityEventDto { quote_amount, lp_amount, executed_at: chrono::Utc::now(), - } + }; } } @@ -95,7 +95,7 @@ impl TryFrom for KbLiquidityEventDto { "cannot parse liquidity event executed_at '{}': {}", entity.executed_at, error ))); - } + }, }; let slot = match entity.slot { Some(slot) => { @@ -107,12 +107,12 @@ impl TryFrom for KbLiquidityEventDto { "cannot convert liquidity event slot '{}' to u64: {}", slot, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, @@ -129,6 +129,6 @@ impl TryFrom for KbLiquidityEventDto { quote_amount: entity.quote_amount, lp_amount: entity.lp_amount, executed_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/observed_token.rs b/kb_lib/src/db/dtos/observed_token.rs index 8e99b16..abf965c 100644 --- a/kb_lib/src/db/dtos/observed_token.rs +++ b/kb_lib/src/db/dtos/observed_token.rs @@ -38,7 +38,7 @@ impl KbObservedTokenDto { status: crate::KbObservedTokenStatus, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, mint, symbol, @@ -49,16 +49,14 @@ impl KbObservedTokenDto { first_seen_at: now, last_seen_at: now, updated_at: now, - } + }; } } impl TryFrom for KbObservedTokenDto { type Error = crate::KbError; - fn try_from( - entity: crate::KbObservedTokenEntity, - ) -> Result { + fn try_from(entity: crate::KbObservedTokenEntity) -> Result { let status_result = crate::KbObservedTokenStatus::from_i16(entity.status); let status = match status_result { Ok(status) => status, @@ -70,8 +68,7 @@ impl TryFrom for KbObservedTokenDto { Err(error) => { return Err(crate::KbError::Db(format!( "cannot parse observed token first_seen_at '{}': {}", - entity.first_seen_at, - error + entity.first_seen_at, error ))); }, }; @@ -81,8 +78,7 @@ impl TryFrom for KbObservedTokenDto { Err(error) => { return Err(crate::KbError::Db(format!( "cannot parse observed token last_seen_at '{}': {}", - entity.last_seen_at, - error + entity.last_seen_at, error ))); }, }; @@ -92,8 +88,7 @@ impl TryFrom for KbObservedTokenDto { Err(error) => { return Err(crate::KbError::Db(format!( "cannot parse observed token updated_at '{}': {}", - entity.updated_at, - error + entity.updated_at, error ))); }, }; @@ -105,15 +100,14 @@ impl TryFrom for KbObservedTokenDto { Err(error) => { return Err(crate::KbError::Db(format!( "cannot convert observed token decimals '{}' to u8: {}", - decimals, - error + decimals, error ))); }, } }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), mint: entity.mint, symbol: entity.symbol, @@ -124,6 +118,6 @@ impl TryFrom for KbObservedTokenDto { first_seen_at, last_seen_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/onchain_observation.rs b/kb_lib/src/db/dtos/onchain_observation.rs index b9a6eeb..cc96f5d 100644 --- a/kb_lib/src/db/dtos/onchain_observation.rs +++ b/kb_lib/src/db/dtos/onchain_observation.rs @@ -33,7 +33,7 @@ impl KbOnchainObservationDto { slot: std::option::Option, payload: serde_json::Value, ) -> Self { - Self { + return Self { id: None, observation_kind, source_kind, @@ -42,7 +42,7 @@ impl KbOnchainObservationDto { slot, payload, observed_at: chrono::Utc::now(), - } + }; } } @@ -63,7 +63,7 @@ impl TryFrom for KbOnchainObservationDto { "cannot parse on-chain observation observed_at '{}': {}", entity.observed_at, error ))); - } + }, }; let payload_result = serde_json::from_str::(&entity.payload_json); let payload = match payload_result { @@ -73,7 +73,7 @@ impl TryFrom for KbOnchainObservationDto { "cannot parse on-chain observation payload_json '{}': {}", entity.payload_json, error ))); - } + }, }; let slot = match entity.slot { Some(slot) => { @@ -85,12 +85,12 @@ impl TryFrom for KbOnchainObservationDto { "cannot convert on-chain observation slot '{}' to u64: {}", slot, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), observation_kind: entity.observation_kind, source_kind, @@ -99,6 +99,6 @@ impl TryFrom for KbOnchainObservationDto { slot, payload, observed_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pair.rs b/kb_lib/src/db/dtos/pair.rs index 2fd95b6..1e4ffb1 100644 --- a/kb_lib/src/db/dtos/pair.rs +++ b/kb_lib/src/db/dtos/pair.rs @@ -33,7 +33,7 @@ impl KbPairDto { symbol: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, dex_id, pool_id, @@ -42,7 +42,7 @@ impl KbPairDto { symbol, first_seen_at: now, updated_at: now, - } + }; } } @@ -58,7 +58,7 @@ impl TryFrom for KbPairDto { "cannot parse pair first_seen_at '{}': {}", entity.first_seen_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -68,9 +68,9 @@ impl TryFrom for KbPairDto { "cannot parse pair updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, @@ -79,6 +79,6 @@ impl TryFrom for KbPairDto { symbol: entity.symbol, first_seen_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pair_analytic_signal.rs b/kb_lib/src/db/dtos/pair_analytic_signal.rs index 06dd3cd..8a4bd1b 100644 --- a/kb_lib/src/db/dtos/pair_analytic_signal.rs +++ b/kb_lib/src/db/dtos/pair_analytic_signal.rs @@ -45,7 +45,7 @@ impl KbPairAnalyticSignalDto { last_transaction_id: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, pair_id, signal_kind, @@ -58,7 +58,7 @@ impl KbPairAnalyticSignalDto { last_transaction_id, created_at: now, updated_at: now, - } + }; } } @@ -80,7 +80,7 @@ impl TryFrom for KbPairAnalyticSignalDto { "cannot parse pair_analytic_signal signal_value_json '{}': {}", entity.signal_value_json, error ))); - } + }, }; let created_at_result = chrono::DateTime::parse_from_rfc3339(entity.created_at.as_str()); let created_at = match created_at_result { @@ -90,7 +90,7 @@ impl TryFrom for KbPairAnalyticSignalDto { "cannot parse pair_analytic_signal created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(entity.updated_at.as_str()); let updated_at = match updated_at_result { @@ -100,9 +100,9 @@ impl TryFrom for KbPairAnalyticSignalDto { "cannot parse pair_analytic_signal updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), pair_id: entity.pair_id, signal_kind: entity.signal_kind, @@ -115,6 +115,6 @@ impl TryFrom for KbPairAnalyticSignalDto { last_transaction_id: entity.last_transaction_id, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pair_candle.rs b/kb_lib/src/db/dtos/pair_candle.rs index c72f17d..18249b9 100644 --- a/kb_lib/src/db/dtos/pair_candle.rs +++ b/kb_lib/src/db/dtos/pair_candle.rs @@ -64,7 +64,7 @@ impl KbPairCandleDto { last_trade_signature: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, pair_id, timeframe_seconds, @@ -83,7 +83,7 @@ impl KbPairCandleDto { last_trade_signature, created_at: now, updated_at: now, - } + }; } } @@ -99,7 +99,7 @@ impl TryFrom for KbPairCandleDto { "cannot parse pair_candle created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -109,9 +109,9 @@ impl TryFrom for KbPairCandleDto { "cannot parse pair_candle updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), pair_id: entity.pair_id, timeframe_seconds: entity.timeframe_seconds, @@ -130,6 +130,6 @@ impl TryFrom for KbPairCandleDto { last_trade_signature: entity.last_trade_signature, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pair_metric.rs b/kb_lib/src/db/dtos/pair_metric.rs index 9b78d34..78df35d 100644 --- a/kb_lib/src/db/dtos/pair_metric.rs +++ b/kb_lib/src/db/dtos/pair_metric.rs @@ -39,7 +39,7 @@ impl KbPairMetricDto { /// Creates a new pair-metric DTO. pub fn new(pair_id: i64) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, pair_id, first_slot: None, @@ -54,7 +54,7 @@ impl KbPairMetricDto { last_price_quote_per_base: None, created_at: now, updated_at: now, - } + }; } } @@ -70,7 +70,7 @@ impl TryFrom for KbPairMetricDto { "cannot parse pair_metric created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -80,9 +80,9 @@ impl TryFrom for KbPairMetricDto { "cannot parse pair_metric updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), pair_id: entity.pair_id, first_slot: entity.first_slot, @@ -97,6 +97,6 @@ impl TryFrom for KbPairMetricDto { last_price_quote_per_base: entity.last_price_quote_per_base, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pool.rs b/kb_lib/src/db/dtos/pool.rs index f5910df..907dab4 100644 --- a/kb_lib/src/db/dtos/pool.rs +++ b/kb_lib/src/db/dtos/pool.rs @@ -30,7 +30,7 @@ impl KbPoolDto { status: crate::KbPoolStatus, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, dex_id, address, @@ -38,7 +38,7 @@ impl KbPoolDto { status, first_seen_at: now, updated_at: now, - } + }; } } @@ -64,7 +64,7 @@ impl TryFrom for KbPoolDto { "cannot parse pool first_seen_at '{}': {}", entity.first_seen_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -74,9 +74,9 @@ impl TryFrom for KbPoolDto { "cannot parse pool updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, address: entity.address, @@ -84,6 +84,6 @@ impl TryFrom for KbPoolDto { status, first_seen_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pool_listing.rs b/kb_lib/src/db/dtos/pool_listing.rs index 095574b..027dca8 100644 --- a/kb_lib/src/db/dtos/pool_listing.rs +++ b/kb_lib/src/db/dtos/pool_listing.rs @@ -42,7 +42,7 @@ impl KbPoolListingDto { initial_price_quote: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, dex_id, pool_id, @@ -54,7 +54,7 @@ impl KbPoolListingDto { initial_quote_reserve, initial_price_quote, updated_at: now, - } + }; } } @@ -75,7 +75,7 @@ impl TryFrom for KbPoolListingDto { "cannot parse pool_listing detected_at '{}': {}", entity.detected_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -85,9 +85,9 @@ impl TryFrom for KbPoolListingDto { "cannot parse pool_listing updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, @@ -99,6 +99,6 @@ impl TryFrom for KbPoolListingDto { initial_quote_reserve: entity.initial_quote_reserve, initial_price_quote: entity.initial_price_quote, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pool_origin.rs b/kb_lib/src/db/dtos/pool_origin.rs index 871a5d1..ba50a5f 100644 --- a/kb_lib/src/db/dtos/pool_origin.rs +++ b/kb_lib/src/db/dtos/pool_origin.rs @@ -54,7 +54,7 @@ impl KbPoolOriginDto { launch_attribution_id: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, dex_id, pool_id, @@ -70,7 +70,7 @@ impl KbPoolOriginDto { launch_attribution_id, created_at: now, updated_at: now, - } + }; } } @@ -91,7 +91,7 @@ impl TryFrom for KbPoolOriginDto { "cannot parse pool_origin created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -101,9 +101,9 @@ impl TryFrom for KbPoolOriginDto { "cannot parse pool_origin updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, @@ -119,6 +119,6 @@ impl TryFrom for KbPoolOriginDto { launch_attribution_id: entity.launch_attribution_id, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/pool_token.rs b/kb_lib/src/db/dtos/pool_token.rs index 3a0030c..54025ac 100644 --- a/kb_lib/src/db/dtos/pool_token.rs +++ b/kb_lib/src/db/dtos/pool_token.rs @@ -33,7 +33,7 @@ impl KbPoolTokenDto { token_order: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, pool_id, token_id, @@ -42,7 +42,7 @@ impl KbPoolTokenDto { token_order, created_at: now, updated_at: now, - } + }; } } @@ -63,7 +63,7 @@ impl TryFrom for KbPoolTokenDto { "cannot parse pool_token created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -73,9 +73,9 @@ impl TryFrom for KbPoolTokenDto { "cannot parse pool_token updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), pool_id: entity.pool_id, token_id: entity.token_id, @@ -84,6 +84,6 @@ impl TryFrom for KbPoolTokenDto { token_order: entity.token_order, created_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/swap.rs b/kb_lib/src/db/dtos/swap.rs index bbc0718..558a710 100644 --- a/kb_lib/src/db/dtos/swap.rs +++ b/kb_lib/src/db/dtos/swap.rs @@ -54,7 +54,7 @@ impl KbSwapDto { price_quote: std::option::Option, trade_side: crate::KbSwapTradeSide, ) -> Self { - Self { + return Self { id: None, dex_id, pool_id, @@ -70,7 +70,7 @@ impl KbSwapDto { price_quote, trade_side, executed_at: chrono::Utc::now(), - } + }; } } @@ -91,7 +91,7 @@ impl TryFrom for KbSwapDto { "cannot parse swap executed_at '{}': {}", entity.executed_at, error ))); - } + }, }; let slot = match entity.slot { Some(slot) => { @@ -103,12 +103,12 @@ impl TryFrom for KbSwapDto { "cannot convert swap slot '{}' to u64: {}", slot, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, @@ -124,6 +124,6 @@ impl TryFrom for KbSwapDto { price_quote: entity.price_quote, trade_side, executed_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/token.rs b/kb_lib/src/db/dtos/token.rs index 23fc3e4..72a34c5 100644 --- a/kb_lib/src/db/dtos/token.rs +++ b/kb_lib/src/db/dtos/token.rs @@ -36,7 +36,7 @@ impl KbTokenDto { is_quote_token: bool, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, mint, symbol, @@ -46,7 +46,7 @@ impl KbTokenDto { is_quote_token, first_seen_at: now, updated_at: now, - } + }; } } @@ -62,7 +62,7 @@ impl TryFrom for KbTokenDto { "cannot parse token first_seen_at '{}': {}", entity.first_seen_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -72,7 +72,7 @@ impl TryFrom for KbTokenDto { "cannot parse token updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; let decimals = match entity.decimals { Some(decimals) => { @@ -84,12 +84,12 @@ impl TryFrom for KbTokenDto { "cannot convert token decimals '{}' to u8: {}", decimals, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), mint: entity.mint, symbol: entity.symbol, @@ -99,6 +99,6 @@ impl TryFrom for KbTokenDto { is_quote_token: entity.is_quote_token != 0, first_seen_at, updated_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/token_burn_event.rs b/kb_lib/src/db/dtos/token_burn_event.rs index 7f5ade5..a05f673 100644 --- a/kb_lib/src/db/dtos/token_burn_event.rs +++ b/kb_lib/src/db/dtos/token_burn_event.rs @@ -39,7 +39,7 @@ impl KbTokenBurnEventDto { amount: std::string::String, supply_after: std::option::Option, ) -> Self { - Self { + return Self { id: None, token_id, signature, @@ -50,24 +50,21 @@ impl KbTokenBurnEventDto { amount, supply_after, executed_at: chrono::Utc::now(), - } + }; } } impl TryFrom for KbTokenBurnEventDto { type Error = crate::KbError; - fn try_from( - entity: crate::KbTokenBurnEventEntity, - ) -> Result { + fn try_from(entity: crate::KbTokenBurnEventEntity) -> Result { 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::KbError::Db(format!( "cannot parse token burn event executed_at '{}': {}", - entity.executed_at, - error + entity.executed_at, error ))); }, }; @@ -79,15 +76,14 @@ impl TryFrom for KbTokenBurnEventDto { Err(error) => { return Err(crate::KbError::Db(format!( "cannot convert token burn event slot '{}' to u64: {}", - slot, - error + slot, error ))); }, } }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), token_id: entity.token_id, signature: entity.signature, @@ -98,6 +94,6 @@ impl TryFrom for KbTokenBurnEventDto { amount: entity.amount, supply_after: entity.supply_after, executed_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/token_mint_event.rs b/kb_lib/src/db/dtos/token_mint_event.rs index a45b218..646bdd7 100644 --- a/kb_lib/src/db/dtos/token_mint_event.rs +++ b/kb_lib/src/db/dtos/token_mint_event.rs @@ -39,7 +39,7 @@ impl KbTokenMintEventDto { amount: std::string::String, supply_after: std::option::Option, ) -> Self { - Self { + return Self { id: None, token_id, signature, @@ -50,7 +50,7 @@ impl KbTokenMintEventDto { amount, supply_after, executed_at: chrono::Utc::now(), - } + }; } } @@ -66,7 +66,7 @@ impl TryFrom for KbTokenMintEventDto { "cannot parse token mint event executed_at '{}': {}", entity.executed_at, error ))); - } + }, }; let slot = match entity.slot { Some(slot) => { @@ -78,12 +78,12 @@ impl TryFrom for KbTokenMintEventDto { "cannot convert token mint event slot '{}' to u64: {}", slot, error ))); - } + }, } - } + }, None => None, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), token_id: entity.token_id, signature: entity.signature, @@ -94,6 +94,6 @@ impl TryFrom for KbTokenMintEventDto { amount: entity.amount, supply_after: entity.supply_after, executed_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/trade_event.rs b/kb_lib/src/db/dtos/trade_event.rs index 7fa1b79..35340d8 100644 --- a/kb_lib/src/db/dtos/trade_event.rs +++ b/kb_lib/src/db/dtos/trade_event.rs @@ -66,7 +66,7 @@ impl KbTradeEventDto { payload_json: std::string::String, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, dex_id, pool_id, @@ -86,7 +86,7 @@ impl KbTradeEventDto { payload_json, created_at: now, updated_at: now, - } + }; } } @@ -108,7 +108,7 @@ impl TryFrom for KbTradeEventDto { "cannot parse trade_event created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -118,9 +118,9 @@ impl TryFrom for KbTradeEventDto { "cannot parse trade_event updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, @@ -140,14 +140,14 @@ impl TryFrom for KbTradeEventDto { payload_json: entity.payload_json, created_at, updated_at, - }) + }); } } fn kb_trade_side_from_string(value: &str) -> crate::KbSwapTradeSide { match value { - "BuyBase" => crate::KbSwapTradeSide::BuyBase, - "SellBase" => crate::KbSwapTradeSide::SellBase, - _ => crate::KbSwapTradeSide::Unknown, + "BuyBase" => return crate::KbSwapTradeSide::BuyBase, + "SellBase" => return crate::KbSwapTradeSide::SellBase, + _ => return crate::KbSwapTradeSide::Unknown, } } diff --git a/kb_lib/src/db/dtos/wallet.rs b/kb_lib/src/db/dtos/wallet.rs index e61d93b..06065ac 100644 --- a/kb_lib/src/db/dtos/wallet.rs +++ b/kb_lib/src/db/dtos/wallet.rs @@ -24,13 +24,13 @@ impl KbWalletDto { label: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, address, label, first_seen_at: now, last_seen_at: now, - } + }; } } @@ -46,7 +46,7 @@ impl TryFrom for KbWalletDto { "cannot parse wallet first_seen_at '{}': {}", entity.first_seen_at, error ))); - } + }, }; let last_seen_at_result = chrono::DateTime::parse_from_rfc3339(&entity.last_seen_at); let last_seen_at = match last_seen_at_result { @@ -56,14 +56,14 @@ impl TryFrom for KbWalletDto { "cannot parse wallet last_seen_at '{}': {}", entity.last_seen_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), address: entity.address, label: entity.label, first_seen_at, last_seen_at, - }) + }); } } diff --git a/kb_lib/src/db/dtos/wallet_holding.rs b/kb_lib/src/db/dtos/wallet_holding.rs index 8a4e913..8b9f136 100644 --- a/kb_lib/src/db/dtos/wallet_holding.rs +++ b/kb_lib/src/db/dtos/wallet_holding.rs @@ -54,7 +54,7 @@ impl KbWalletHoldingDto { source_endpoint_name: std::option::Option, ) -> Self { let now = chrono::Utc::now(); - Self { + return Self { id: None, wallet_id, token_id, @@ -70,7 +70,7 @@ impl KbWalletHoldingDto { source_endpoint_name, created_at: now, updated_at: now, - } + }; } } @@ -91,7 +91,7 @@ impl TryFrom for KbWalletHoldingDto { "cannot parse wallet_holding created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -101,9 +101,9 @@ impl TryFrom for KbWalletHoldingDto { "cannot parse wallet_holding updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), wallet_id: entity.wallet_id, token_id: entity.token_id, diff --git a/kb_lib/src/db/dtos/wallet_participation.rs b/kb_lib/src/db/dtos/wallet_participation.rs index bbdf81f..555f9bf 100644 --- a/kb_lib/src/db/dtos/wallet_participation.rs +++ b/kb_lib/src/db/dtos/wallet_participation.rs @@ -52,8 +52,7 @@ impl KbWalletParticipationDto { pair_id, role.as_str(), ); - - Self { + return Self { id: None, wallet_id, transaction_id, @@ -66,7 +65,7 @@ impl KbWalletParticipationDto { source_endpoint_name, created_at: now, updated_at: now, - } + }; } } @@ -87,7 +86,7 @@ impl TryFrom for KbWalletParticipationDto { "cannot parse wallet_participation created_at '{}': {}", entity.created_at, error ))); - } + }, }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { @@ -97,9 +96,9 @@ impl TryFrom for KbWalletParticipationDto { "cannot parse wallet_participation updated_at '{}': {}", entity.updated_at, error ))); - } + }, }; - Ok(Self { + return Ok(Self { id: Some(entity.id), wallet_id: entity.wallet_id, transaction_id: entity.transaction_id, @@ -112,7 +111,7 @@ impl TryFrom for KbWalletParticipationDto { source_endpoint_name: entity.source_endpoint_name, created_at, updated_at, - }) + }); } } @@ -127,8 +126,8 @@ fn kb_build_wallet_participation_unique_key( let decoded_event_id_value = decoded_event_id.unwrap_or_default(); let pool_id_value = pool_id.unwrap_or_default(); let pair_id_value = pair_id.unwrap_or_default(); - format!( + return format!( "{}:{}:{}:{}:{}:{}", wallet_id, transaction_id, decoded_event_id_value, pool_id_value, pair_id_value, role - ) + ); } diff --git a/kb_lib/src/db/queries.rs b/kb_lib/src/db/queries.rs index 0c4651c..9190eca 100644 --- a/kb_lib/src/db/queries.rs +++ b/kb_lib/src/db/queries.rs @@ -48,6 +48,7 @@ pub use chain_slot::get_chain_slot; pub use chain_slot::list_recent_chain_slots; pub use chain_slot::upsert_chain_slot; pub use chain_transaction::get_chain_transaction_by_signature; +pub use chain_transaction::list_chain_transaction_signatures_for_replay; pub use chain_transaction::list_recent_chain_transactions; pub use chain_transaction::upsert_chain_transaction; pub use db_metadata::get_db_metadata; @@ -59,6 +60,7 @@ pub use dex::get_dex_by_code; pub use dex::list_dexes; pub use dex::upsert_dex; pub use dex_decoded_event::get_dex_decoded_event_by_key; +pub use dex_decoded_event::get_latest_pump_fun_create_payload_by_mint; pub use dex_decoded_event::list_dex_decoded_events_by_transaction_id; pub use dex_decoded_event::upsert_dex_decoded_event; pub use known_http_endpoint::get_known_http_endpoint; @@ -85,6 +87,7 @@ pub use onchain_observation::insert_onchain_observation; pub use onchain_observation::list_recent_onchain_observations; pub use pair::get_pair_by_pool_id; pub use pair::list_pairs; +pub use pair::update_pair_symbol; pub use pair::upsert_pair; pub use pair_analytic_signal::get_pair_analytic_signal_by_key; pub use pair_analytic_signal::list_pair_analytic_signals_by_pair_id; @@ -108,8 +111,10 @@ pub use pool_token::list_pool_tokens_by_pool_id; pub use pool_token::upsert_pool_token; pub use swap::list_recent_swaps; pub use swap::upsert_swap; +pub use token::get_token_by_id; pub use token::get_token_by_mint; pub use token::list_tokens; +pub use token::list_tokens_missing_metadata; pub use token::upsert_token; pub use token_burn_event::list_recent_token_burn_events; pub use token_burn_event::upsert_token_burn_event; diff --git a/kb_lib/src/db/queries/analysis_signal.rs b/kb_lib/src/db/queries/analysis_signal.rs index 6f413b8..7fa5171 100644 --- a/kb_lib/src/db/queries/analysis_signal.rs +++ b/kb_lib/src/db/queries/analysis_signal.rs @@ -15,7 +15,7 @@ pub async fn insert_analysis_signal( "cannot serialize analysis signal payload: {}", error ))); - } + }, }; match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { @@ -49,10 +49,10 @@ VALUES (?, ?, ?, ?, ?, ?, ?) "cannot insert kb_analysis_signals on sqlite: {}", error ))); - } + }, }; - Ok(query_result.last_insert_rowid()) - } + return Ok(query_result.last_insert_rowid()); + }, } } @@ -92,7 +92,7 @@ LIMIT ? "cannot list analysis signals on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -103,8 +103,8 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/chain_instruction.rs b/kb_lib/src/db/queries/chain_instruction.rs index d17e4e5..36d34d5 100644 --- a/kb_lib/src/db/queries/chain_instruction.rs +++ b/kb_lib/src/db/queries/chain_instruction.rs @@ -58,10 +58,10 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "cannot insert kb_chain_instructions on sqlite: {}", error ))); - } + }, }; - Ok(insert_result.last_insert_rowid()) - } + return Ok(insert_result.last_insert_rowid()); + }, } } @@ -103,7 +103,7 @@ ORDER BY instruction_index ASC, inner_instruction_index ASC, id ASC "cannot list kb_chain_instructions for transaction_id '{}' on sqlite: {}", transaction_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -114,8 +114,8 @@ ORDER BY instruction_index ASC, inner_instruction_index ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -141,8 +141,8 @@ WHERE transaction_id = ? transaction_id, error ))); } - Ok(()) - } + return Ok(()); + }, } } @@ -163,9 +163,9 @@ mod tests { use_wal: true, }, }; - crate::KbDatabase::connect_and_initialize(&config) + return crate::KbDatabase::connect_and_initialize(&config) .await - .expect("database init must succeed") + .expect("database init must succeed"); } async fn make_transaction(database: &crate::KbDatabase) -> i64 { @@ -179,9 +179,9 @@ mod tests { None, r#"{"transaction":{"message":{"instructions":[]}}}"#.to_string(), ); - crate::upsert_chain_transaction(database, &dto) + return crate::upsert_chain_transaction(database, &dto) .await - .expect("chain transaction upsert must succeed") + .expect("chain transaction upsert must succeed"); } #[tokio::test] diff --git a/kb_lib/src/db/queries/chain_slot.rs b/kb_lib/src/db/queries/chain_slot.rs index 403e59d..9a3213d 100644 --- a/kb_lib/src/db/queries/chain_slot.rs +++ b/kb_lib/src/db/queries/chain_slot.rs @@ -15,7 +15,7 @@ pub async fn upsert_chain_slot( "cannot convert chain slot '{}' to i64: {}", dto.slot, error ))); - } + }, }; let parent_slot = match dto.parent_slot { Some(parent_slot) => { @@ -27,9 +27,9 @@ pub async fn upsert_chain_slot( "cannot convert chain parent_slot '{}' to i64: {}", parent_slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -63,8 +63,8 @@ ON CONFLICT(slot) DO UPDATE SET error ))); } - Ok(dto.slot) - } + return Ok(dto.slot); + }, } } @@ -81,7 +81,7 @@ pub async fn get_chain_slot( "cannot convert requested chain slot '{}' to i64: {}", slot, error ))); - } + }, }; match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { @@ -108,19 +108,19 @@ LIMIT 1 "cannot fetch kb_chain_slots for slot '{}' on sqlite: {}", slot, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbChainSlotDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -157,7 +157,7 @@ LIMIT ? "cannot list kb_chain_slots on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -168,8 +168,8 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -190,9 +190,9 @@ mod tests { use_wal: true, }, }; - crate::KbDatabase::connect_and_initialize(&config) + return crate::KbDatabase::connect_and_initialize(&config) .await - .expect("database init must succeed") + .expect("database init must succeed"); } #[tokio::test] diff --git a/kb_lib/src/db/queries/chain_transaction.rs b/kb_lib/src/db/queries/chain_transaction.rs index c2a99e0..a12bd93 100644 --- a/kb_lib/src/db/queries/chain_transaction.rs +++ b/kb_lib/src/db/queries/chain_transaction.rs @@ -17,9 +17,9 @@ pub async fn upsert_chain_transaction( "cannot convert chain transaction slot '{}' to i64: {}", slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -80,13 +80,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_chain_transactions id for signature '{}' on sqlite: {}", - dto.signature, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_chain_transactions id for signature '{}' on sqlite: {}", + dto.signature, error + ))); + }, } - } + }, } } @@ -126,19 +128,19 @@ LIMIT 1 "cannot fetch kb_chain_transactions for signature '{}' on sqlite: {}", signature, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbChainTransactionDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -181,7 +183,7 @@ LIMIT ? "cannot list kb_chain_transactions on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -192,8 +194,49 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, + } +} + +/// Lists persisted chain transaction signatures for local pipeline replay. +pub async fn list_chain_transaction_signatures_for_replay( + database: &crate::KbDatabase, + limit: std::option::Option, +) -> Result, crate::KbError> { + match database.connection() { + crate::KbDatabaseConnection::Sqlite(pool) => { + let effective_limit = match limit { + Some(limit) => { + if limit <= 0 { + 10_000 + } else { + limit + } + }, + None => 10_000, + }; + let query_result = sqlx::query_scalar::( + r#" +SELECT signature +FROM kb_chain_transactions +ORDER BY id ASC +LIMIT ? + "#, + ) + .bind(effective_limit) + .fetch_all(pool) + .await; + match query_result { + Ok(signatures) => return Ok(signatures), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot list kb_chain_transactions signatures for local replay on sqlite: {}", + error + ))); + }, + } + }, } } @@ -214,9 +257,9 @@ mod tests { use_wal: true, }, }; - crate::KbDatabase::connect_and_initialize(&config) + return crate::KbDatabase::connect_and_initialize(&config) .await - .expect("database init must succeed") + .expect("database init must succeed"); } #[tokio::test] @@ -249,10 +292,7 @@ mod tests { assert_eq!(fetched.signature, "sig-chain-transaction-1"); assert_eq!(fetched.slot, Some(515151)); assert_eq!(fetched.block_time_unix, Some(1_700_000_001)); - assert_eq!( - fetched.source_endpoint_name, - Some("helius_primary_http".to_string()) - ); + assert_eq!(fetched.source_endpoint_name, Some("helius_primary_http".to_string())); assert_eq!(fetched.version_text, Some("0".to_string())); assert_eq!(fetched.meta_json, Some(r#"{"fee":5000}"#.to_string())); let listed = crate::list_recent_chain_transactions(&database, 10) diff --git a/kb_lib/src/db/queries/db_metadata.rs b/kb_lib/src/db/queries/db_metadata.rs index 46d163b..1d7b54c 100644 --- a/kb_lib/src/db/queries/db_metadata.rs +++ b/kb_lib/src/db/queries/db_metadata.rs @@ -29,13 +29,15 @@ ON CONFLICT(key) DO UPDATE SET .execute(pool) .await; match query_result { - Ok(_) => Ok(()), - Err(error) => Err(crate::KbError::Db(format!( - "cannot upsert kb_db_metadata on sqlite: {}", - error - ))), + Ok(_) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot upsert kb_db_metadata on sqlite: {}", + error + ))); + }, } - } + }, } } @@ -67,19 +69,19 @@ LIMIT 1 "cannot read kb_db_metadata '{}' on sqlite: {}", key, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbDbMetadataDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -108,7 +110,7 @@ ORDER BY key ASC "cannot list kb_db_metadata on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -119,8 +121,8 @@ ORDER BY key ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -146,9 +148,7 @@ mod tests { .await .expect("database init must succeed"); let dto = crate::KbDbMetadataDto::new("schema_version".to_string(), "0.5.0".to_string()); - crate::upsert_db_metadata(&database, &dto) - .await - .expect("upsert must succeed"); + crate::upsert_db_metadata(&database, &dto).await.expect("upsert must succeed"); let fetched = crate::get_db_metadata(&database, "schema_version") .await .expect("fetch must succeed"); @@ -156,9 +156,7 @@ mod tests { let fetched = fetched.expect("metadata must exist"); assert_eq!(fetched.key, "schema_version"); assert_eq!(fetched.value, "0.5.0"); - let listed = crate::list_db_metadata(&database) - .await - .expect("list must succeed"); + let listed = crate::list_db_metadata(&database).await.expect("list must succeed"); assert!(!listed.is_empty()); } } diff --git a/kb_lib/src/db/queries/db_runtime_event.rs b/kb_lib/src/db/queries/db_runtime_event.rs index 0fde3c6..6494383 100644 --- a/kb_lib/src/db/queries/db_runtime_event.rs +++ b/kb_lib/src/db/queries/db_runtime_event.rs @@ -35,10 +35,10 @@ VALUES (?, ?, ?, ?, ?) "cannot insert kb_db_runtime_events on sqlite: {}", error ))); - } + }, }; - Ok(query_result.last_insert_rowid()) - } + return Ok(query_result.last_insert_rowid()); + }, } } @@ -76,7 +76,7 @@ LIMIT ? "cannot list runtime events on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -87,8 +87,8 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/dex.rs b/kb_lib/src/db/queries/dex.rs index 8914e98..aeaf1b4 100644 --- a/kb_lib/src/db/queries/dex.rs +++ b/kb_lib/src/db/queries/dex.rs @@ -56,13 +56,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_dexes id for code '{}' on sqlite: {}", - dto.code, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_dexes id for code '{}' on sqlite: {}", + dto.code, error + ))); + }, } - } + }, } } @@ -99,19 +101,19 @@ LIMIT 1 "cannot read kb_dexes '{}' on sqlite: {}", code, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbDexDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -145,7 +147,7 @@ ORDER BY code ASC "cannot list kb_dexes on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -156,8 +158,8 @@ ORDER BY code ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -184,13 +186,7 @@ mod tests { .expect("database init must succeed"); let dex_id = crate::upsert_dex( &database, - &crate::KbDexDto::new( - "raydium".to_string(), - "Raydium".to_string(), - None, - None, - true, - ), + &crate::KbDexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), ) .await .expect("dex upsert must succeed"); @@ -200,9 +196,7 @@ mod tests { .expect("get dex must succeed"); assert!(dex.is_some()); assert_eq!(dex.expect("dex must exist").name, "Raydium"); - let dexes = crate::list_dexes(&database) - .await - .expect("list dexes must succeed"); + let dexes = crate::list_dexes(&database).await.expect("list dexes must succeed"); assert_eq!(dexes.len(), 1); } } diff --git a/kb_lib/src/db/queries/dex_decoded_event.rs b/kb_lib/src/db/queries/dex_decoded_event.rs index c65e172..f068f48 100644 --- a/kb_lib/src/db/queries/dex_decoded_event.rs +++ b/kb_lib/src/db/queries/dex_decoded_event.rs @@ -77,13 +77,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_dex_decoded_events id on sqlite: {}", - error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_dex_decoded_events id on sqlite: {}", + error + ))); + }, } - } + }, } } @@ -135,19 +137,19 @@ LIMIT 1 "cannot fetch kb_dex_decoded_events on sqlite: {}", error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbDexDecodedEventDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -189,7 +191,7 @@ ORDER BY id ASC "cannot list kb_dex_decoded_events on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -200,8 +202,48 @@ ORDER BY id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, + } +} + +/// Returns the latest Pump.fun create payload associated with a token mint. +pub async fn get_latest_pump_fun_create_payload_by_mint( + database: &crate::KbDatabase, + mint: &str, +) -> Result, crate::KbError> { + match database.connection() { + crate::KbDatabaseConnection::Sqlite(pool) => { + let payload_result = sqlx::query_scalar::( + r#" +SELECT payload_json +FROM kb_dex_decoded_events +WHERE protocol_name = 'pump_fun' + AND event_kind IN ('pump_fun.create', 'pump_fun.create_v2_token') + AND ( + token_a_mint = ? + OR json_extract(payload_json, '$.mint') = ? + OR json_extract(payload_json, '$.tokenMint') = ? + ) +ORDER BY id DESC +LIMIT 1 + "#, + ) + .bind(mint) + .bind(mint) + .bind(mint) + .fetch_optional(pool) + .await; + match payload_result { + Ok(payload_option) => return Ok(payload_option), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot read latest pump.fun create payload for mint '{}' on sqlite: {}", + mint, error + ))); + }, + } + }, } } @@ -228,7 +270,7 @@ mod tests { }; let database_result = crate::KbDatabase::connect_and_initialize(&config).await; match database_result { - Ok(database) => database, + Ok(database) => return database, Err(error) => panic!("database init must succeed: {}", error), } } diff --git a/kb_lib/src/db/queries/known_http_endpoint.rs b/kb_lib/src/db/queries/known_http_endpoint.rs index 8e25cbc..d890850 100644 --- a/kb_lib/src/db/queries/known_http_endpoint.rs +++ b/kb_lib/src/db/queries/known_http_endpoint.rs @@ -46,13 +46,15 @@ ON CONFLICT(name) DO UPDATE SET .execute(pool) .await; match query_result { - Ok(_) => Ok(()), - Err(error) => Err(crate::KbError::Db(format!( - "cannot upsert kb_known_http_endpoints on sqlite: {}", - error - ))), + Ok(_) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot upsert kb_known_http_endpoints on sqlite: {}", + error + ))); + }, } - } + }, } } @@ -88,19 +90,19 @@ LIMIT 1 "cannot read known http endpoint '{}' on sqlite: {}", name, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbKnownHttpEndpointDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -133,7 +135,7 @@ ORDER BY name ASC "cannot list known http endpoints on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -144,8 +146,8 @@ ORDER BY name ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -187,9 +189,7 @@ mod tests { let fetched = fetched.expect("endpoint must exist"); assert_eq!(fetched.provider, "helius"); assert_eq!(fetched.roles.len(), 2); - let listed = crate::list_known_http_endpoints(&database) - .await - .expect("list must succeed"); + let listed = crate::list_known_http_endpoints(&database).await.expect("list must succeed"); assert_eq!(listed.len(), 1); } } diff --git a/kb_lib/src/db/queries/known_ws_endpoint.rs b/kb_lib/src/db/queries/known_ws_endpoint.rs index 31e22cd..c1ec778 100644 --- a/kb_lib/src/db/queries/known_ws_endpoint.rs +++ b/kb_lib/src/db/queries/known_ws_endpoint.rs @@ -12,7 +12,6 @@ pub async fn upsert_known_ws_endpoint( Ok(entity) => entity, Err(error) => return Err(error), }; - match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query( @@ -46,13 +45,15 @@ ON CONFLICT(name) DO UPDATE SET .execute(pool) .await; match query_result { - Ok(_) => Ok(()), - Err(error) => Err(crate::KbError::Db(format!( - "cannot upsert kb_known_ws_endpoints on sqlite: {}", - error - ))), + Ok(_) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot upsert kb_known_ws_endpoints on sqlite: {}", + error + ))); + }, } - } + }, } } @@ -88,19 +89,19 @@ LIMIT 1 "cannot read known ws endpoint '{}' on sqlite: {}", name, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbKnownWsEndpointDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -133,7 +134,7 @@ ORDER BY name ASC "cannot list known ws endpoints on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -144,8 +145,8 @@ ORDER BY name ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -187,9 +188,7 @@ mod tests { let fetched = fetched.expect("endpoint must exist"); assert_eq!(fetched.provider, "solana"); assert_eq!(fetched.roles.len(), 2); - let listed = crate::list_known_ws_endpoints(&database) - .await - .expect("list must succeed"); + let listed = crate::list_known_ws_endpoints(&database).await.expect("list must succeed"); assert_eq!(listed.len(), 1); } } diff --git a/kb_lib/src/db/queries/launch_attribution.rs b/kb_lib/src/db/queries/launch_attribution.rs index 9aa25c1..8d2414b 100644 --- a/kb_lib/src/db/queries/launch_attribution.rs +++ b/kb_lib/src/db/queries/launch_attribution.rs @@ -68,13 +68,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_launch_attributions id for decoded_event_id '{}' on sqlite: {}", - dto.decoded_event_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_launch_attributions id for decoded_event_id '{}' on sqlite: {}", + dto.decoded_event_id, error + ))); + }, } - } + }, } } @@ -85,9 +87,8 @@ pub async fn get_launch_attribution_by_decoded_event_id( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, launch_surface_id, @@ -105,10 +106,10 @@ FROM kb_launch_attributions WHERE decoded_event_id = ? LIMIT 1 "#, - ) - .bind(decoded_event_id) - .fetch_optional(pool) - .await; + ) + .bind(decoded_event_id) + .fetch_optional(pool) + .await; let entity_option = match query_result { Ok(entity_option) => entity_option, Err(error) => { @@ -116,13 +117,13 @@ LIMIT 1 "cannot read kb_launch_attributions by decoded_event_id '{}' on sqlite: {}", decoded_event_id, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbLaunchAttributionDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbLaunchAttributionDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -133,9 +134,8 @@ pub async fn list_launch_attributions_by_pool_id( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, launch_surface_id, @@ -153,10 +153,10 @@ FROM kb_launch_attributions WHERE pool_id = ? ORDER BY attributed_at ASC, id ASC "#, - ) - .bind(pool_id) - .fetch_all(pool) - .await; + ) + .bind(pool_id) + .fetch_all(pool) + .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { @@ -164,7 +164,7 @@ ORDER BY attributed_at ASC, id ASC "cannot list kb_launch_attributions by pool_id '{}' on sqlite: {}", pool_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -175,7 +175,7 @@ ORDER BY attributed_at ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/launch_surface.rs b/kb_lib/src/db/queries/launch_surface.rs index 879a118..5a7c0bb 100644 --- a/kb_lib/src/db/queries/launch_surface.rs +++ b/kb_lib/src/db/queries/launch_surface.rs @@ -53,13 +53,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_launch_surfaces id for code '{}' on sqlite: {}", - dto.code, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_launch_surfaces id for code '{}' on sqlite: {}", + dto.code, error + ))); + }, } - } + }, } } @@ -70,9 +72,8 @@ pub async fn get_launch_surface_by_code( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, code, @@ -85,10 +86,10 @@ FROM kb_launch_surfaces WHERE code = ? LIMIT 1 "#, - ) - .bind(code) - .fetch_optional(pool) - .await; + ) + .bind(code) + .fetch_optional(pool) + .await; let entity_option = match query_result { Ok(entity_option) => entity_option, Err(error) => { @@ -96,13 +97,13 @@ LIMIT 1 "cannot read kb_launch_surfaces '{}' on sqlite: {}", code, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbLaunchSurfaceDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbLaunchSurfaceDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -112,9 +113,8 @@ pub async fn list_launch_surfaces( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, code, @@ -126,9 +126,9 @@ SELECT FROM kb_launch_surfaces ORDER BY code ASC "#, - ) - .fetch_all(pool) - .await; + ) + .fetch_all(pool) + .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { @@ -136,7 +136,7 @@ ORDER BY code ASC "cannot list kb_launch_surfaces on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -147,7 +147,7 @@ ORDER BY code ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/launch_surface_key.rs b/kb_lib/src/db/queries/launch_surface_key.rs index f04444d..0753e30 100644 --- a/kb_lib/src/db/queries/launch_surface_key.rs +++ b/kb_lib/src/db/queries/launch_surface_key.rs @@ -50,13 +50,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_launch_surface_keys id for '{}:{}' on sqlite: {}", - dto.match_kind, dto.match_value, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_launch_surface_keys id for '{}:{}' on sqlite: {}", + dto.match_kind, dto.match_value, error + ))); + }, } - } + }, } } @@ -68,9 +70,8 @@ pub async fn get_launch_surface_key_by_match( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, launch_surface_id, @@ -82,11 +83,11 @@ FROM kb_launch_surface_keys WHERE match_kind = ? AND match_value = ? LIMIT 1 "#, - ) - .bind(match_kind) - .bind(match_value) - .fetch_optional(pool) - .await; + ) + .bind(match_kind) + .bind(match_value) + .fetch_optional(pool) + .await; let entity_option = match query_result { Ok(entity_option) => entity_option, Err(error) => { @@ -94,13 +95,13 @@ LIMIT 1 "cannot read kb_launch_surface_keys '{}:{}' on sqlite: {}", match_kind, match_value, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbLaunchSurfaceKeyDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbLaunchSurfaceKeyDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -111,9 +112,8 @@ pub async fn list_launch_surface_keys_by_surface_id( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, launch_surface_id, @@ -125,10 +125,10 @@ FROM kb_launch_surface_keys WHERE launch_surface_id = ? ORDER BY match_kind ASC, match_value ASC "#, - ) - .bind(launch_surface_id) - .fetch_all(pool) - .await; + ) + .bind(launch_surface_id) + .fetch_all(pool) + .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { @@ -136,7 +136,7 @@ ORDER BY match_kind ASC, match_value ASC "cannot list kb_launch_surface_keys by surface_id '{}' on sqlite: {}", launch_surface_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -147,7 +147,7 @@ ORDER BY match_kind ASC, match_value ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/liquidity_event.rs b/kb_lib/src/db/queries/liquidity_event.rs index bf45239..5720710 100644 --- a/kb_lib/src/db/queries/liquidity_event.rs +++ b/kb_lib/src/db/queries/liquidity_event.rs @@ -17,9 +17,9 @@ pub async fn upsert_liquidity_event( "cannot convert liquidity event slot '{}' to i64: {}", slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -96,13 +96,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_liquidity_events id for signature '{}' and instruction_index '{}' on sqlite: {}", - dto.signature, dto.instruction_index, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_liquidity_events id for signature '{}' and instruction_index '{}' on sqlite: {}", + dto.signature, dto.instruction_index, error + ))); + }, } - } + }, } } @@ -150,7 +152,7 @@ LIMIT ? "cannot list kb_liquidity_events on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -161,7 +163,7 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/observed_token.rs b/kb_lib/src/db/queries/observed_token.rs index 67b0c77..6e66733 100644 --- a/kb_lib/src/db/queries/observed_token.rs +++ b/kb_lib/src/db/queries/observed_token.rs @@ -63,13 +63,15 @@ LIMIT 1 .fetch_one(pool) .await; match select_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_observed_tokens id for mint '{}' on sqlite: {}", - dto.mint, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_observed_tokens id for mint '{}' on sqlite: {}", + dto.mint, error + ))); + }, } - } + }, } } @@ -108,19 +110,19 @@ LIMIT 1 "cannot read observed token '{}' on sqlite: {}", mint, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbObservedTokenDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -162,7 +164,7 @@ LIMIT ? "cannot list observed tokens on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -173,8 +175,8 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -222,9 +224,7 @@ mod tests { assert_eq!(fetched.symbol.as_deref(), Some("WSOL")); assert_eq!(fetched.decimals, Some(9)); assert_eq!(fetched.status, crate::KbObservedTokenStatus::Active); - let listed = crate::list_observed_tokens(&database, 10) - .await - .expect("list must succeed"); + let listed = crate::list_observed_tokens(&database, 10).await.expect("list must succeed"); assert_eq!(listed.len(), 1); } } diff --git a/kb_lib/src/db/queries/onchain_observation.rs b/kb_lib/src/db/queries/onchain_observation.rs index 83023af..9808b13 100644 --- a/kb_lib/src/db/queries/onchain_observation.rs +++ b/kb_lib/src/db/queries/onchain_observation.rs @@ -15,7 +15,7 @@ pub async fn insert_onchain_observation( "cannot serialize on-chain observation payload: {}", error ))); - } + }, }; let slot_i64 = match dto.slot { Some(slot) => { @@ -27,9 +27,9 @@ pub async fn insert_onchain_observation( "cannot convert on-chain observation slot '{}' to i64: {}", slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -64,10 +64,10 @@ VALUES (?, ?, ?, ?, ?, ?, ?) "cannot insert kb_onchain_observations on sqlite: {}", error ))); - } + }, }; - Ok(query_result.last_insert_rowid()) - } + return Ok(query_result.last_insert_rowid()); + }, } } @@ -107,7 +107,7 @@ LIMIT ? "cannot list on-chain observations on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -118,8 +118,8 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/pair.rs b/kb_lib/src/db/queries/pair.rs index b046ea0..a5555e0 100644 --- a/kb_lib/src/db/queries/pair.rs +++ b/kb_lib/src/db/queries/pair.rs @@ -25,7 +25,11 @@ ON CONFLICT(pool_id) DO UPDATE SET dex_id = excluded.dex_id, base_token_id = excluded.base_token_id, quote_token_id = excluded.quote_token_id, - symbol = excluded.symbol, + symbol = CASE + WHEN excluded.symbol IS NOT NULL AND trim(excluded.symbol) <> '' + THEN excluded.symbol + ELSE kb_pairs.symbol + END, updated_at = excluded.updated_at "#, ) @@ -56,13 +60,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pairs id for pool_id '{}' on sqlite: {}", - dto.pool_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pairs id for pool_id '{}' on sqlite: {}", + dto.pool_id, error + ))); + }, } - } + }, } } @@ -99,19 +105,54 @@ LIMIT 1 "cannot read kb_pairs by pool_id '{}' on sqlite: {}", pool_id, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbPairDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, + } +} + +/// Updates the display symbol of one normalized pair row. +pub async fn update_pair_symbol( + database: &crate::KbDatabase, + pair_id: i64, + symbol: std::option::Option<&str>, +) -> Result { + match database.connection() { + crate::KbDatabaseConnection::Sqlite(pool) => { + let query_result = sqlx::query( + r#" +UPDATE kb_pairs +SET + symbol = ?, + updated_at = ? +WHERE id = ? + "#, + ) + .bind(symbol) + .bind(chrono::Utc::now().to_rfc3339()) + .bind(pair_id) + .execute(pool) + .await; + match query_result { + Ok(done) => return Ok(done.rows_affected() > 0), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot update kb_pairs symbol for id '{}' on sqlite: {}", + pair_id, error + ))); + }, + } + }, } } @@ -145,7 +186,7 @@ ORDER BY id ASC "cannot list kb_pairs on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -156,8 +197,8 @@ ORDER BY id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -184,13 +225,7 @@ mod tests { .expect("database init must succeed"); let dex_id = crate::upsert_dex( &database, - &crate::KbDexDto::new( - "raydium".to_string(), - "Raydium".to_string(), - None, - None, - true, - ), + &crate::KbDexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), ) .await .expect("dex upsert must succeed"); @@ -248,13 +283,8 @@ mod tests { .await .expect("get pair must succeed"); assert!(pair.is_some()); - assert_eq!( - pair.expect("pair must exist").symbol.as_deref(), - Some("BASE/WSOL") - ); - let pairs = crate::list_pairs(&database) - .await - .expect("list pairs must succeed"); + assert_eq!(pair.expect("pair must exist").symbol.as_deref(), Some("BASE/WSOL")); + let pairs = crate::list_pairs(&database).await.expect("list pairs must succeed"); assert_eq!(pairs.len(), 1); } } diff --git a/kb_lib/src/db/queries/pair_analytic_signal.rs b/kb_lib/src/db/queries/pair_analytic_signal.rs index 5fa63ec..ca1c65a 100644 --- a/kb_lib/src/db/queries/pair_analytic_signal.rs +++ b/kb_lib/src/db/queries/pair_analytic_signal.rs @@ -15,7 +15,7 @@ pub async fn upsert_pair_analytic_signal( "cannot serialize pair analytic signal payload: {}", error ))); - } + }, }; match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { @@ -77,13 +77,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pair_analytic_signals id on sqlite: {}", - error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pair_analytic_signals id on sqlite: {}", + error + ))); + }, } - } + }, } } @@ -97,9 +99,8 @@ pub async fn get_pair_analytic_signal_by_key( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, pair_id, @@ -117,13 +118,13 @@ FROM kb_pair_analytic_signals WHERE pair_id = ? AND signal_kind = ? AND timeframe_seconds = ? AND bucket_start_unix = ? LIMIT 1 "#, - ) - .bind(pair_id) - .bind(signal_kind) - .bind(timeframe_seconds) - .bind(bucket_start_unix) - .fetch_optional(pool) - .await; + ) + .bind(pair_id) + .bind(signal_kind) + .bind(timeframe_seconds) + .bind(bucket_start_unix) + .fetch_optional(pool) + .await; let entity_option = match query_result { Ok(entity_option) => entity_option, Err(error) => { @@ -131,13 +132,13 @@ LIMIT 1 "cannot read kb_pair_analytic_signals by key on sqlite: {}", error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbPairAnalyticSignalDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbPairAnalyticSignalDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -148,9 +149,8 @@ pub async fn list_pair_analytic_signals_by_pair_id( ) -> Result, crate::KbError> { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { - let query_result = - sqlx::query_as::( - r#" + let query_result = sqlx::query_as::( + r#" SELECT id, pair_id, @@ -168,10 +168,10 @@ FROM kb_pair_analytic_signals WHERE pair_id = ? ORDER BY timeframe_seconds ASC, bucket_start_unix ASC, signal_kind ASC, id ASC "#, - ) - .bind(pair_id) - .fetch_all(pool) - .await; + ) + .bind(pair_id) + .fetch_all(pool) + .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { @@ -179,7 +179,7 @@ ORDER BY timeframe_seconds ASC, bucket_start_unix ASC, signal_kind ASC, id ASC "cannot list kb_pair_analytic_signals by pair_id '{}' on sqlite: {}", pair_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -190,7 +190,7 @@ ORDER BY timeframe_seconds ASC, bucket_start_unix ASC, signal_kind ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/pair_candle.rs b/kb_lib/src/db/queries/pair_candle.rs index 2211de5..6b2a99a 100644 --- a/kb_lib/src/db/queries/pair_candle.rs +++ b/kb_lib/src/db/queries/pair_candle.rs @@ -87,13 +87,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pair_candles id for pair_id '{}' timeframe '{}' bucket '{}' on sqlite: {}", - dto.pair_id, dto.timeframe_seconds, dto.bucket_start_unix, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pair_candles id for pair_id '{}' timeframe '{}' bucket '{}' on sqlite: {}", + dto.pair_id, dto.timeframe_seconds, dto.bucket_start_unix, error + ))); + }, } - } + }, } } @@ -144,13 +146,13 @@ LIMIT 1 "cannot read kb_pair_candles by key on sqlite: {}", error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbPairCandleDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbPairCandleDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -199,7 +201,7 @@ ORDER BY bucket_start_unix ASC, id ASC "cannot list kb_pair_candles by pair_id '{}' timeframe '{}' on sqlite: {}", pair_id, timeframe_seconds, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -210,7 +212,7 @@ ORDER BY bucket_start_unix ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/pair_metric.rs b/kb_lib/src/db/queries/pair_metric.rs index 3dc33d0..6727b6b 100644 --- a/kb_lib/src/db/queries/pair_metric.rs +++ b/kb_lib/src/db/queries/pair_metric.rs @@ -74,13 +74,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pair_metrics id for pair_id '{}' on sqlite: {}", - dto.pair_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pair_metrics id for pair_id '{}' on sqlite: {}", + dto.pair_id, error + ))); + }, } - } + }, } } @@ -123,13 +125,13 @@ LIMIT 1 "cannot read kb_pair_metrics by pair_id '{}' on sqlite: {}", pair_id, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbPairMetricDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbPairMetricDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -169,7 +171,7 @@ ORDER BY pair_id ASC "cannot list kb_pair_metrics on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -180,7 +182,7 @@ ORDER BY pair_id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/pool.rs b/kb_lib/src/db/queries/pool.rs index 076e6b2..c4f4e49 100644 --- a/kb_lib/src/db/queries/pool.rs +++ b/kb_lib/src/db/queries/pool.rs @@ -53,13 +53,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pools id for address '{}' on sqlite: {}", - dto.address, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pools id for address '{}' on sqlite: {}", + dto.address, error + ))); + }, } - } + }, } } @@ -95,19 +97,19 @@ LIMIT 1 "cannot read kb_pools '{}' on sqlite: {}", address, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbPoolDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -140,7 +142,7 @@ ORDER BY id ASC "cannot list kb_pools on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -151,8 +153,8 @@ ORDER BY id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -179,13 +181,7 @@ mod tests { .expect("database init must succeed"); let dex_id = crate::upsert_dex( &database, - &crate::KbDexDto::new( - "raydium".to_string(), - "Raydium".to_string(), - None, - None, - true, - ), + &crate::KbDexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), ) .await .expect("dex upsert must succeed"); @@ -206,13 +202,8 @@ mod tests { .await .expect("get pool must succeed"); assert!(pool.is_some()); - assert_eq!( - pool.expect("pool must exist").pool_kind, - crate::KbPoolKind::Amm - ); - let pools = crate::list_pools(&database) - .await - .expect("list pools must succeed"); + assert_eq!(pool.expect("pool must exist").pool_kind, crate::KbPoolKind::Amm); + let pools = crate::list_pools(&database).await.expect("list pools must succeed"); assert_eq!(pools.len(), 1); } } diff --git a/kb_lib/src/db/queries/pool_listing.rs b/kb_lib/src/db/queries/pool_listing.rs index eef7717..1d63156 100644 --- a/kb_lib/src/db/queries/pool_listing.rs +++ b/kb_lib/src/db/queries/pool_listing.rs @@ -66,13 +66,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pool_listings id for pool_id '{}' on sqlite: {}", - dto.pool_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pool_listings id for pool_id '{}' on sqlite: {}", + dto.pool_id, error + ))); + }, } - } + }, } } @@ -112,19 +114,19 @@ LIMIT 1 "cannot read kb_pool_listings by pool_id '{}' on sqlite: {}", pool_id, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbPoolListingDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } @@ -161,7 +163,7 @@ ORDER BY detected_at ASC, id ASC "cannot list kb_pool_listings on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -172,8 +174,8 @@ ORDER BY detected_at ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -200,13 +202,7 @@ mod tests { .expect("database init must succeed"); let dex_id = crate::upsert_dex( &database, - &crate::KbDexDto::new( - "raydium".to_string(), - "Raydium".to_string(), - None, - None, - true, - ), + &crate::KbDexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), ) .await .expect("dex upsert must succeed"); diff --git a/kb_lib/src/db/queries/pool_origin.rs b/kb_lib/src/db/queries/pool_origin.rs index 16cf575..3d990fd 100644 --- a/kb_lib/src/db/queries/pool_origin.rs +++ b/kb_lib/src/db/queries/pool_origin.rs @@ -69,13 +69,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pool_origins id for pool_id '{}' on sqlite: {}", - dto.pool_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pool_origins id for pool_id '{}' on sqlite: {}", + dto.pool_id, error + ))); + }, } - } + }, } } @@ -119,13 +121,13 @@ LIMIT 1 "cannot read kb_pool_origins by pool_id '{}' on sqlite: {}", pool_id, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbPoolOriginDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbPoolOriginDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -166,7 +168,7 @@ ORDER BY created_at ASC, id ASC "cannot list kb_pool_origins on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -177,7 +179,7 @@ ORDER BY created_at ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/pool_token.rs b/kb_lib/src/db/queries/pool_token.rs index c15fe56..62302d2 100644 --- a/kb_lib/src/db/queries/pool_token.rs +++ b/kb_lib/src/db/queries/pool_token.rs @@ -56,13 +56,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_pool_tokens id on sqlite: {}", - error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_pool_tokens id on sqlite: {}", + error + ))); + }, } - } + }, } } @@ -99,7 +101,7 @@ ORDER BY token_order ASC, id ASC "cannot list kb_pool_tokens for pool_id '{}' on sqlite: {}", pool_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -110,8 +112,8 @@ ORDER BY token_order ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -138,13 +140,7 @@ mod tests { .expect("database init must succeed"); let dex_id = crate::upsert_dex( &database, - &crate::KbDexDto::new( - "raydium".to_string(), - "Raydium".to_string(), - None, - None, - true, - ), + &crate::KbDexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), ) .await .expect("dex upsert must succeed"); diff --git a/kb_lib/src/db/queries/swap.rs b/kb_lib/src/db/queries/swap.rs index ca15847..842d824 100644 --- a/kb_lib/src/db/queries/swap.rs +++ b/kb_lib/src/db/queries/swap.rs @@ -17,9 +17,9 @@ pub async fn upsert_swap( "cannot convert swap slot '{}' to i64: {}", slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -93,13 +93,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_swaps id for signature '{}' and instruction_index '{}' on sqlite: {}", - dto.signature, dto.instruction_index, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_swaps id for signature '{}' and instruction_index '{}' on sqlite: {}", + dto.signature, dto.instruction_index, error + ))); + }, } - } + }, } } @@ -146,7 +148,7 @@ LIMIT ? "cannot list kb_swaps on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -157,7 +159,7 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/token.rs b/kb_lib/src/db/queries/token.rs index 6414e8f..1887571 100644 --- a/kb_lib/src/db/queries/token.rs +++ b/kb_lib/src/db/queries/token.rs @@ -60,13 +60,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_tokens id for mint '{}' on sqlite: {}", - dto.mint, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_tokens id for mint '{}' on sqlite: {}", + dto.mint, error + ))); + }, } - } + }, } } @@ -104,22 +106,71 @@ LIMIT 1 "cannot read kb_tokens '{}' on sqlite: {}", mint, error ))); - } + }, }; match entity_option { Some(entity) => { let dto_result = crate::KbTokenDto::try_from(entity); match dto_result { - Ok(dto) => Ok(Some(dto)), - Err(error) => Err(error), + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), } - } - None => Ok(None), + }, + None => return Ok(None), } - } + }, } } +/// Reads one normalized token row by internal id. +pub async fn get_token_by_id( + database: &crate::KbDatabase, + token_id: i64, +) -> Result, crate::KbError> { + match database.connection() { + crate::KbDatabaseConnection::Sqlite(pool) => { + let query_result = sqlx::query_as::( + r#" +SELECT + id, + mint, + symbol, + name, + decimals, + token_program, + is_quote_token, + first_seen_at, + updated_at +FROM kb_tokens +WHERE id = ? +LIMIT 1 + "#, + ) + .bind(token_id) + .fetch_optional(pool) + .await; + let entity_option = match query_result { + Ok(entity_option) => entity_option, + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot read kb_tokens id '{}' on sqlite: {}", + token_id, error + ))); + }, + }; + match entity_option { + Some(entity) => { + let dto_result = crate::KbTokenDto::try_from(entity); + match dto_result { + Ok(dto) => return Ok(Some(dto)), + Err(error) => return Err(error), + } + }, + None => return Ok(None), + } + }, + } +} /// Lists all normalized token rows ordered by mint. pub async fn list_tokens( @@ -152,7 +203,7 @@ ORDER BY mint ASC, id ASC "cannot list kb_tokens on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -163,7 +214,161 @@ ORDER BY mint ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } -} \ No newline at end of file +} + +/// Lists token rows whose display or mint metadata is incomplete. +pub async fn list_tokens_missing_metadata( + database: &crate::KbDatabase, + limit: std::option::Option, +) -> Result, crate::KbError> { + match database.connection() { + crate::KbDatabaseConnection::Sqlite(pool) => { + let entities_result = match limit { + Some(limit) => { + sqlx::query_as::( + r#" +SELECT + id, + mint, + symbol, + name, + decimals, + token_program, + is_quote_token, + first_seen_at, + updated_at +FROM kb_tokens +WHERE symbol IS NULL + OR trim(symbol) = '' + OR name IS NULL + OR trim(name) = '' + OR decimals IS NULL + OR token_program IS NULL + OR trim(token_program) = '' +ORDER BY updated_at ASC, id ASC +LIMIT ? + "#, + ) + .bind(limit) + .fetch_all(pool) + .await + }, + None => { + sqlx::query_as::( + r#" +SELECT + id, + mint, + symbol, + name, + decimals, + token_program, + is_quote_token, + first_seen_at, + updated_at +FROM kb_tokens +WHERE symbol IS NULL + OR trim(symbol) = '' + OR name IS NULL + OR trim(name) = '' + OR decimals IS NULL + OR token_program IS NULL + OR trim(token_program) = '' +ORDER BY updated_at ASC, id ASC + "#, + ) + .fetch_all(pool) + .await + }, + }; + let entities = match entities_result { + Ok(entities) => entities, + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot list kb_tokens missing metadata on sqlite: {}", + error + ))); + }, + }; + let mut dtos = std::vec::Vec::new(); + for entity in entities { + let dto_result = crate::KbTokenDto::try_from(entity); + let dto = match dto_result { + Ok(dto) => dto, + Err(error) => return Err(error), + }; + dtos.push(dto); + } + return Ok(dtos); + }, + } +} + +#[cfg(test)] +mod tests { + async fn make_database() -> std::sync::Arc { + let tempdir_result = tempfile::tempdir(); + let tempdir = match tempdir_result { + Ok(tempdir) => tempdir, + Err(error) => panic!("tempdir must succeed: {}", error), + }; + let database_path = tempdir.path().join("token_query.sqlite3"); + let config = crate::KbDatabaseConfig { + enabled: true, + backend: crate::KbDatabaseBackend::Sqlite, + sqlite: crate::KbSqliteDatabaseConfig { + path: database_path.to_string_lossy().to_string(), + create_if_missing: true, + busy_timeout_ms: 5000, + max_connections: 1, + auto_initialize_schema: true, + use_wal: true, + }, + }; + let database_result = crate::KbDatabase::connect_and_initialize(&config).await; + let database = match database_result { + Ok(database) => database, + Err(error) => panic!("database init must succeed: {}", error), + }; + return std::sync::Arc::new(database); + } + + #[tokio::test] + async fn list_tokens_missing_metadata_only_returns_incomplete_rows() { + let database = make_database().await; + let incomplete = crate::KbTokenDto::new( + "IncompleteMint111".to_string(), + None, + None, + None, + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + false, + ); + let complete = crate::KbTokenDto::new( + "CompleteMint111".to_string(), + Some("CMP".to_string()), + Some("Complete".to_string()), + Some(6), + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + false, + ); + let incomplete_result = crate::upsert_token(database.as_ref(), &incomplete).await; + if let Err(error) = incomplete_result { + panic!("incomplete token upsert must succeed: {}", error); + } + let complete_result = crate::upsert_token(database.as_ref(), &complete).await; + if let Err(error) = complete_result { + panic!("complete token upsert must succeed: {}", error); + } + let missing_result = crate::list_tokens_missing_metadata(database.as_ref(), None).await; + let missing = match missing_result { + Ok(missing) => missing, + Err(error) => panic!("missing metadata list must succeed: {}", error), + }; + assert_eq!(missing.len(), 1); + assert_eq!(missing[0].mint, "IncompleteMint111"); + } +} diff --git a/kb_lib/src/db/queries/token_burn_event.rs b/kb_lib/src/db/queries/token_burn_event.rs index f8ed06b..9e6f349 100644 --- a/kb_lib/src/db/queries/token_burn_event.rs +++ b/kb_lib/src/db/queries/token_burn_event.rs @@ -17,9 +17,9 @@ pub async fn upsert_token_burn_event( "cannot convert token burn event slot '{}' to i64: {}", slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -78,13 +78,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_token_burn_events id for signature '{}' and instruction_index '{}' on sqlite: {}", - dto.signature, dto.instruction_index, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_token_burn_events id for signature '{}' and instruction_index '{}' on sqlite: {}", + dto.signature, dto.instruction_index, error + ))); + }, } - } + }, } } @@ -126,7 +128,7 @@ LIMIT ? "cannot list kb_token_burn_events on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -137,8 +139,8 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -165,13 +167,7 @@ mod tests { .expect("database init must succeed"); let dex_id = crate::upsert_dex( &database, - &crate::KbDexDto::new( - "raydium".to_string(), - "Raydium".to_string(), - None, - None, - true, - ), + &crate::KbDexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), ) .await .expect("dex upsert must succeed"); @@ -299,9 +295,7 @@ mod tests { assert!(liquidity_id > 0); assert!(mint_id > 0); assert!(burn_id > 0); - let swaps = crate::list_recent_swaps(&database, 10) - .await - .expect("swaps list must succeed"); + let swaps = crate::list_recent_swaps(&database, 10).await.expect("swaps list must succeed"); let liquidity_events = crate::list_recent_liquidity_events(&database, 10) .await .expect("liquidity list must succeed"); diff --git a/kb_lib/src/db/queries/token_mint_event.rs b/kb_lib/src/db/queries/token_mint_event.rs index bd50158..02bd64e 100644 --- a/kb_lib/src/db/queries/token_mint_event.rs +++ b/kb_lib/src/db/queries/token_mint_event.rs @@ -17,9 +17,9 @@ pub async fn upsert_token_mint_event( "cannot convert token mint event slot '{}' to i64: {}", slot, error ))); - } + }, } - } + }, None => None, }; match database.connection() { @@ -78,13 +78,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_token_mint_events id for signature '{}' and instruction_index '{}' on sqlite: {}", - dto.signature, dto.instruction_index, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_token_mint_events id for signature '{}' and instruction_index '{}' on sqlite: {}", + dto.signature, dto.instruction_index, error + ))); + }, } - } + }, } } @@ -126,7 +128,7 @@ LIMIT ? "cannot list kb_token_mint_events on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -137,7 +139,7 @@ LIMIT ? }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/trade_event.rs b/kb_lib/src/db/queries/trade_event.rs index 257a74a..58920b8 100644 --- a/kb_lib/src/db/queries/trade_event.rs +++ b/kb_lib/src/db/queries/trade_event.rs @@ -90,13 +90,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_trade_events id for decoded_event_id '{}' on sqlite: {}", - dto.decoded_event_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_trade_events id for decoded_event_id '{}' on sqlite: {}", + dto.decoded_event_id, error + ))); + }, } - } + }, } } @@ -144,13 +146,13 @@ LIMIT 1 "cannot read kb_trade_events by decoded_event_id '{}' on sqlite: {}", decoded_event_id, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbTradeEventDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbTradeEventDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -198,7 +200,7 @@ ORDER BY created_at ASC, id ASC "cannot list kb_trade_events by pair_id '{}' on sqlite: {}", pair_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -209,8 +211,8 @@ ORDER BY created_at ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -258,7 +260,7 @@ ORDER BY id ASC "cannot list kb_trade_events by transaction_id '{}' on sqlite: {}", transaction_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -269,15 +271,15 @@ ORDER BY id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } fn kb_trade_side_to_string(value: crate::KbSwapTradeSide) -> &'static str { match value { - crate::KbSwapTradeSide::BuyBase => "BuyBase", - crate::KbSwapTradeSide::SellBase => "SellBase", - crate::KbSwapTradeSide::Unknown => "Unknown", + crate::KbSwapTradeSide::BuyBase => return "BuyBase", + crate::KbSwapTradeSide::SellBase => return "SellBase", + crate::KbSwapTradeSide::Unknown => return "Unknown", } } diff --git a/kb_lib/src/db/queries/wallet.rs b/kb_lib/src/db/queries/wallet.rs index 32c6411..41a36a8 100644 --- a/kb_lib/src/db/queries/wallet.rs +++ b/kb_lib/src/db/queries/wallet.rs @@ -47,13 +47,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_wallets id for address '{}' on sqlite: {}", - dto.address, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_wallets id for address '{}' on sqlite: {}", + dto.address, error + ))); + }, } - } + }, } } @@ -87,13 +89,13 @@ LIMIT 1 "cannot read kb_wallets '{}' on sqlite: {}", address, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbWalletDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbWalletDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -124,7 +126,7 @@ ORDER BY address ASC "cannot list kb_wallets on sqlite: {}", error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -135,7 +137,7 @@ ORDER BY address ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/wallet_holding.rs b/kb_lib/src/db/queries/wallet_holding.rs index cc07e57..876cd34 100644 --- a/kb_lib/src/db/queries/wallet_holding.rs +++ b/kb_lib/src/db/queries/wallet_holding.rs @@ -76,13 +76,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_wallet_holdings id for wallet_id '{}' token_id '{}' on sqlite: {}", - dto.wallet_id, dto.token_id, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_wallet_holdings id for wallet_id '{}' token_id '{}' on sqlite: {}", + dto.wallet_id, dto.token_id, error + ))); + }, } - } + }, } } @@ -128,13 +130,13 @@ LIMIT 1 "cannot read kb_wallet_holdings by wallet_id '{}' token_id '{}' on sqlite: {}", wallet_id, token_id, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbWalletHoldingDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbWalletHoldingDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -178,7 +180,7 @@ ORDER BY token_id ASC, id ASC "cannot list kb_wallet_holdings by wallet_id '{}' on sqlite: {}", wallet_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -189,7 +191,7 @@ ORDER BY token_id ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/queries/wallet_participation.rs b/kb_lib/src/db/queries/wallet_participation.rs index 72396c8..b0ac520 100644 --- a/kb_lib/src/db/queries/wallet_participation.rs +++ b/kb_lib/src/db/queries/wallet_participation.rs @@ -60,13 +60,15 @@ LIMIT 1 .fetch_one(pool) .await; match id_result { - Ok(id) => Ok(id), - Err(error) => Err(crate::KbError::Db(format!( - "cannot fetch kb_wallet_participations id for unique_key '{}' on sqlite: {}", - dto.unique_key, error - ))), + Ok(id) => return Ok(id), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot fetch kb_wallet_participations id for unique_key '{}' on sqlite: {}", + dto.unique_key, error + ))); + }, } - } + }, } } @@ -107,13 +109,13 @@ LIMIT 1 "cannot read kb_wallet_participations by unique_key '{}' on sqlite: {}", unique_key, error ))); - } + }, }; match entity_option { - Some(entity) => crate::KbWalletParticipationDto::try_from(entity).map(Some), - None => Ok(None), + Some(entity) => return crate::KbWalletParticipationDto::try_from(entity).map(Some), + None => return Ok(None), } - } + }, } } @@ -154,7 +156,7 @@ ORDER BY created_at ASC, id ASC "cannot list kb_wallet_participations by wallet_id '{}' on sqlite: {}", wallet_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -165,8 +167,8 @@ ORDER BY created_at ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } @@ -207,7 +209,7 @@ ORDER BY created_at ASC, id ASC "cannot list kb_wallet_participations by pool_id '{}' on sqlite: {}", pool_id, error ))); - } + }, }; let mut dtos = std::vec::Vec::new(); for entity in entities { @@ -218,7 +220,7 @@ ORDER BY created_at ASC, id ASC }; dtos.push(dto); } - Ok(dtos) - } + return Ok(dtos); + }, } } diff --git a/kb_lib/src/db/schema.rs b/kb_lib/src/db/schema.rs index 48add4f..2b71139 100644 --- a/kb_lib/src/db/schema.rs +++ b/kb_lib/src/db/schema.rs @@ -342,8 +342,8 @@ pub(crate) async fn ensure_schema(database: &crate::KbDatabase) -> Result<(), cr if let Err(error) = result { return Err(error); } - Ok(()) - } + return Ok(()); + }, } } @@ -355,11 +355,13 @@ async fn execute_sqlite_schema_statement( ) -> Result<(), crate::KbError> { let execute_result = sqlx::query(statement_sql).execute(pool).await; match execute_result { - Ok(_) => Ok(()), - Err(error) => Err(crate::KbError::Db(format!( - "cannot initialize sqlite schema statement '{}': {}", - statement_name, error - ))), + Ok(_) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot initialize sqlite schema statement '{}': {}", + statement_name, error + ))); + }, } } @@ -373,14 +375,14 @@ async fn update_schema_version_metadata( ); let upsert_result = crate::upsert_db_metadata(database, &schema_version).await; match upsert_result { - Ok(_) => Ok(()), - Err(error) => Err(error), + Ok(_) => return Ok(()), + Err(error) => return Err(error), } } /// Creates `kb_db_metadata`. async fn create_kb_db_metadata_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_db_metadata_table", r#" @@ -391,14 +393,14 @@ CREATE TABLE IF NOT EXISTS kb_db_metadata ( ) "#, ) - .await + .await; } /// Creates `kb_known_http_endpoints`. async fn create_kb_known_http_endpoints_table( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_known_http_endpoints_table", r#" @@ -413,12 +415,12 @@ CREATE TABLE IF NOT EXISTS kb_known_http_endpoints ( ) "#, ) - .await + .await; } /// Creates `kb_known_ws_endpoints`. async fn create_kb_known_ws_endpoints_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_known_ws_endpoints_table", r#" @@ -433,12 +435,12 @@ CREATE TABLE IF NOT EXISTS kb_known_ws_endpoints ( ) "#, ) - .await + .await; } /// Creates `kb_db_runtime_events`. async fn create_kb_db_runtime_events_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_db_runtime_events_table", r#" @@ -452,14 +454,14 @@ CREATE TABLE IF NOT EXISTS kb_db_runtime_events ( ) "#, ) - .await + .await; } /// Creates index on `kb_db_runtime_events(created_at)`. async fn create_kb_idx_db_runtime_events_created_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_db_runtime_events_created_at", r#" @@ -467,12 +469,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_db_runtime_events_created_at ON kb_db_runtime_events (created_at) "#, ) - .await + .await; } /// Creates `kb_observed_tokens`. async fn create_kb_observed_tokens_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_observed_tokens_table", r#" @@ -490,12 +492,12 @@ CREATE TABLE IF NOT EXISTS kb_observed_tokens ( ) "#, ) - .await + .await; } /// Creates unique index on `kb_observed_tokens(mint)`. async fn create_kb_idx_observed_tokens_mint(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_observed_tokens_mint", r#" @@ -503,14 +505,14 @@ CREATE UNIQUE INDEX IF NOT EXISTS kb_idx_observed_tokens_mint ON kb_observed_tokens (mint) "#, ) - .await + .await; } /// Creates index on `kb_observed_tokens(status)`. async fn create_kb_idx_observed_tokens_status( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_observed_tokens_status", r#" @@ -518,14 +520,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_observed_tokens_status ON kb_observed_tokens (status) "#, ) - .await + .await; } /// Creates `kb_onchain_observations`. async fn create_kb_onchain_observations_table( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_onchain_observations_table", r#" @@ -541,14 +543,14 @@ CREATE TABLE IF NOT EXISTS kb_onchain_observations ( ) "#, ) - .await + .await; } /// Creates index on `kb_onchain_observations(object_key)`. async fn create_kb_idx_onchain_observations_object_key( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_onchain_observations_object_key", r#" @@ -556,14 +558,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_onchain_observations_object_key ON kb_onchain_observations (object_key) "#, ) - .await + .await; } /// Creates index on `kb_onchain_observations(observed_at)`. async fn create_kb_idx_onchain_observations_observed_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_onchain_observations_observed_at", r#" @@ -571,12 +573,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_onchain_observations_observed_at ON kb_onchain_observations (observed_at) "#, ) - .await + .await; } /// Creates `kb_analysis_signals`. async fn create_kb_analysis_signals_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_analysis_signals_table", r#" @@ -593,14 +595,14 @@ CREATE TABLE IF NOT EXISTS kb_analysis_signals ( ) "#, ) - .await + .await; } /// Creates index on `kb_analysis_signals(object_key)`. async fn create_kb_idx_analysis_signals_object_key( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_analysis_signals_object_key", r#" @@ -608,14 +610,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_analysis_signals_object_key ON kb_analysis_signals (object_key) "#, ) - .await + .await; } /// Creates index on `kb_analysis_signals(created_at)`. async fn create_kb_idx_analysis_signals_created_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_analysis_signals_created_at", r#" @@ -623,12 +625,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_analysis_signals_created_at ON kb_analysis_signals (created_at) "#, ) - .await + .await; } /// Creates `kb_dexes`. async fn create_kb_dexes_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_dexes_table", r#" @@ -644,12 +646,12 @@ CREATE TABLE IF NOT EXISTS kb_dexes ( ) "#, ) - .await + .await; } /// Creates `kb_tokens`. async fn create_kb_tokens_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_tokens_table", r#" @@ -666,12 +668,12 @@ CREATE TABLE IF NOT EXISTS kb_tokens ( ) "#, ) - .await + .await; } /// Creates index on `kb_tokens(token_program)`. async fn create_kb_idx_tokens_token_program(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_tokens_token_program", r#" @@ -679,14 +681,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_tokens_token_program ON kb_tokens (token_program) "#, ) - .await + .await; } /// Creates index on `kb_tokens(is_quote_token)`. async fn create_kb_idx_tokens_is_quote_token( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_tokens_is_quote_token", r#" @@ -694,12 +696,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_tokens_is_quote_token ON kb_tokens (is_quote_token) "#, ) - .await + .await; } /// Creates `kb_pools`. async fn create_kb_pools_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pools_table", r#" @@ -715,12 +717,12 @@ CREATE TABLE IF NOT EXISTS kb_pools ( ) "#, ) - .await + .await; } /// Creates index on `kb_pools(dex_id)`. async fn create_kb_idx_pools_dex_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pools_dex_id", r#" @@ -728,12 +730,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pools_dex_id ON kb_pools (dex_id) "#, ) - .await + .await; } /// Creates `kb_pairs`. async fn create_kb_pairs_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pairs_table", r#" @@ -753,12 +755,12 @@ CREATE TABLE IF NOT EXISTS kb_pairs ( ) "#, ) - .await + .await; } /// Creates index on `kb_pairs(dex_id)`. async fn create_kb_idx_pairs_dex_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pairs_dex_id", r#" @@ -766,12 +768,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pairs_dex_id ON kb_pairs (dex_id) "#, ) - .await + .await; } /// Creates index on `kb_pairs(base_token_id)`. async fn create_kb_idx_pairs_base_token_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pairs_base_token_id", r#" @@ -779,12 +781,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pairs_base_token_id ON kb_pairs (base_token_id) "#, ) - .await + .await; } /// Creates index on `kb_pairs(quote_token_id)`. async fn create_kb_idx_pairs_quote_token_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pairs_quote_token_id", r#" @@ -792,12 +794,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pairs_quote_token_id ON kb_pairs (quote_token_id) "#, ) - .await + .await; } /// Creates `kb_pool_tokens`. async fn create_kb_pool_tokens_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pool_tokens_table", r#" @@ -816,12 +818,12 @@ CREATE TABLE IF NOT EXISTS kb_pool_tokens ( ) "#, ) - .await + .await; } /// Creates index on `kb_pool_tokens(pool_id)`. async fn create_kb_idx_pool_tokens_pool_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_tokens_pool_id", r#" @@ -829,12 +831,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_tokens_pool_id ON kb_pool_tokens (pool_id) "#, ) - .await + .await; } /// Creates index on `kb_pool_tokens(token_id)`. async fn create_kb_idx_pool_tokens_token_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_tokens_token_id", r#" @@ -842,12 +844,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_tokens_token_id ON kb_pool_tokens (token_id) "#, ) - .await + .await; } /// Creates `kb_pool_listings`. async fn create_kb_pool_listings_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pool_listings_table", r#" @@ -869,14 +871,14 @@ CREATE TABLE IF NOT EXISTS kb_pool_listings ( ) "#, ) - .await + .await; } /// Creates index on `kb_pool_listings(detected_at)`. async fn create_kb_idx_pool_listings_detected_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_listings_detected_at", r#" @@ -884,12 +886,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_listings_detected_at ON kb_pool_listings (detected_at) "#, ) - .await + .await; } /// Creates index on `kb_pool_listings(dex_id)`. async fn create_kb_idx_pool_listings_dex_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_listings_dex_id", r#" @@ -897,12 +899,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_listings_dex_id ON kb_pool_listings (dex_id) "#, ) - .await + .await; } /// Creates `kb_swaps`. async fn create_kb_swaps_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_swaps_table", r#" @@ -931,12 +933,12 @@ CREATE TABLE IF NOT EXISTS kb_swaps ( ) "#, ) - .await + .await; } /// Creates index on `kb_swaps(pool_id)`. async fn create_kb_idx_swaps_pool_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_swaps_pool_id", r#" @@ -944,12 +946,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_swaps_pool_id ON kb_swaps (pool_id) "#, ) - .await + .await; } /// Creates index on `kb_swaps(executed_at)`. async fn create_kb_idx_swaps_executed_at(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_swaps_executed_at", r#" @@ -957,12 +959,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_swaps_executed_at ON kb_swaps (executed_at) "#, ) - .await + .await; } /// Creates index on `kb_swaps(pair_id)`. async fn create_kb_idx_swaps_pair_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_swaps_pair_id", r#" @@ -970,12 +972,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_swaps_pair_id ON kb_swaps (pair_id) "#, ) - .await + .await; } /// Creates index on `kb_swaps(slot)`. async fn create_kb_idx_swaps_slot(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_swaps_slot", r#" @@ -983,12 +985,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_swaps_slot ON kb_swaps (slot) "#, ) - .await + .await; } /// Creates `kb_liquidity_events`. async fn create_kb_liquidity_events_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_liquidity_events_table", r#" @@ -1019,14 +1021,14 @@ CREATE TABLE IF NOT EXISTS kb_liquidity_events ( ) "#, ) - .await + .await; } /// Creates index on `kb_liquidity_events(pool_id)`. async fn create_kb_idx_liquidity_events_pool_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_liquidity_events_pool_id", r#" @@ -1034,14 +1036,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_liquidity_events_pool_id ON kb_liquidity_events (pool_id) "#, ) - .await + .await; } /// Creates index on `kb_liquidity_events(executed_at)`. async fn create_kb_idx_liquidity_events_executed_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_liquidity_events_executed_at", r#" @@ -1049,14 +1051,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_liquidity_events_executed_at ON kb_liquidity_events (executed_at) "#, ) - .await + .await; } /// Creates index on `kb_liquidity_events(pair_id)`. async fn create_kb_idx_liquidity_events_pair_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_liquidity_events_pair_id", r#" @@ -1064,14 +1066,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_liquidity_events_pair_id ON kb_liquidity_events (pair_id) "#, ) - .await + .await; } /// Creates index on `kb_liquidity_events(slot)`. async fn create_kb_idx_liquidity_events_slot( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_liquidity_events_slot", r#" @@ -1079,12 +1081,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_liquidity_events_slot ON kb_liquidity_events (slot) "#, ) - .await + .await; } /// Creates `kb_token_mint_events`. async fn create_kb_token_mint_events_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_token_mint_events_table", r#" @@ -1104,14 +1106,14 @@ CREATE TABLE IF NOT EXISTS kb_token_mint_events ( ) "#, ) - .await + .await; } /// Creates index on `kb_token_mint_events(token_id)`. async fn create_kb_idx_token_mint_events_token_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_token_mint_events_token_id", r#" @@ -1119,14 +1121,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_token_mint_events_token_id ON kb_token_mint_events (token_id) "#, ) - .await + .await; } /// Creates index on `kb_token_mint_events(executed_at)`. async fn create_kb_idx_token_mint_events_executed_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_token_mint_events_executed_at", r#" @@ -1134,12 +1136,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_token_mint_events_executed_at ON kb_token_mint_events (executed_at) "#, ) - .await + .await; } /// Creates `kb_token_burn_events`. async fn create_kb_token_burn_events_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_token_burn_events_table", r#" @@ -1159,14 +1161,14 @@ CREATE TABLE IF NOT EXISTS kb_token_burn_events ( ) "#, ) - .await + .await; } /// Creates index on `kb_token_burn_events(token_id)`. async fn create_kb_idx_token_burn_events_token_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_token_burn_events_token_id", r#" @@ -1174,14 +1176,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_token_burn_events_token_id ON kb_token_burn_events (token_id) "#, ) - .await + .await; } /// Creates index on `kb_token_burn_events(executed_at)`. async fn create_kb_idx_token_burn_events_executed_at( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_token_burn_events_executed_at", r#" @@ -1189,12 +1191,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_token_burn_events_executed_at ON kb_token_burn_events (executed_at) "#, ) - .await + .await; } /// Creates `kb_chain_slots`. async fn create_kb_chain_slots_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_chain_slots_table", r#" @@ -1207,12 +1209,12 @@ CREATE TABLE IF NOT EXISTS kb_chain_slots ( ) "#, ) - .await + .await; } /// Creates `kb_chain_transactions`. async fn create_kb_chain_transactions_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_chain_transactions_table", r#" @@ -1232,14 +1234,14 @@ CREATE TABLE IF NOT EXISTS kb_chain_transactions ( ) "#, ) - .await + .await; } /// Creates index on `kb_chain_transactions(slot)`. async fn create_kb_idx_chain_transactions_slot( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_chain_transactions_slot", r#" @@ -1247,12 +1249,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_chain_transactions_slot ON kb_chain_transactions (slot) "#, ) - .await + .await; } /// Creates `kb_chain_instructions`. async fn create_kb_chain_instructions_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_chain_instructions_table", r#" @@ -1275,14 +1277,14 @@ CREATE TABLE IF NOT EXISTS kb_chain_instructions ( ) "#, ) - .await + .await; } /// Creates index on `kb_chain_instructions(transaction_id)`. async fn create_kb_idx_chain_instructions_transaction_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_chain_instructions_transaction_id", r#" @@ -1290,14 +1292,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_chain_instructions_transaction_id ON kb_chain_instructions (transaction_id) "#, ) - .await + .await; } /// Creates index on `kb_chain_instructions(program_id)`. async fn create_kb_idx_chain_instructions_program_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_chain_instructions_program_id", r#" @@ -1305,12 +1307,12 @@ CREATE INDEX IF NOT EXISTS kb_idx_chain_instructions_program_id ON kb_chain_instructions (program_id) "#, ) - .await + .await; } /// Creates `kb_dex_decoded_events`. async fn create_kb_dex_decoded_events_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_dex_decoded_events_table", r#" @@ -1333,14 +1335,14 @@ CREATE TABLE IF NOT EXISTS kb_dex_decoded_events ( ) "#, ) - .await + .await; } /// Creates index on `kb_dex_decoded_events(transaction_id)`. async fn create_kb_idx_dex_decoded_events_transaction_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_dex_decoded_events_transaction_id", r#" @@ -1348,14 +1350,14 @@ CREATE INDEX IF NOT EXISTS kb_idx_dex_decoded_events_transaction_id ON kb_dex_decoded_events (transaction_id) "#, ) - .await + .await; } /// Creates unique index on `(transaction_id, instruction_id, event_kind)`. async fn create_kb_uq_dex_decoded_events_transaction_instruction_event( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_uq_dex_decoded_events_transaction_instruction_event", r#" @@ -1363,11 +1365,11 @@ CREATE UNIQUE INDEX IF NOT EXISTS kb_uq_dex_decoded_events_transaction_instructi ON kb_dex_decoded_events (transaction_id, instruction_id, event_kind) "#, ) - .await + .await; } async fn create_kb_launch_surfaces_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_launch_surfaces_table", r#" @@ -1382,13 +1384,13 @@ CREATE TABLE IF NOT EXISTS kb_launch_surfaces ( ) "#, ) - .await + .await; } async fn create_kb_launch_surface_keys_table( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_launch_surface_keys_table", r#" @@ -1404,13 +1406,13 @@ CREATE TABLE IF NOT EXISTS kb_launch_surface_keys ( ) "#, ) - .await + .await; } async fn create_kb_idx_launch_surface_keys_surface_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_launch_surface_keys_surface_id", r#" @@ -1418,13 +1420,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_launch_surface_keys_surface_id ON kb_launch_surface_keys(launch_surface_id) "#, ) - .await + .await; } async fn create_kb_launch_attributions_table( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_launch_attributions_table", r#" @@ -1450,13 +1452,13 @@ CREATE TABLE IF NOT EXISTS kb_launch_attributions ( ) "#, ) - .await + .await; } async fn create_kb_idx_launch_attributions_surface_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_launch_attributions_surface_id", r#" @@ -1464,13 +1466,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_launch_attributions_surface_id ON kb_launch_attributions(launch_surface_id) "#, ) - .await + .await; } async fn create_kb_idx_launch_attributions_pool_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_launch_attributions_pool_id", r#" @@ -1478,11 +1480,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_launch_attributions_pool_id ON kb_launch_attributions(pool_id) "#, ) - .await + .await; } async fn create_kb_pool_origins_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pool_origins_table", r#" @@ -1512,11 +1514,11 @@ CREATE TABLE IF NOT EXISTS kb_pool_origins ( ) "#, ) - .await + .await; } async fn create_kb_idx_pool_origins_dex_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_origins_dex_id", r#" @@ -1524,11 +1526,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_origins_dex_id ON kb_pool_origins(dex_id) "#, ) - .await + .await; } async fn create_kb_idx_pool_origins_pair_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_origins_pair_id", r#" @@ -1536,13 +1538,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_origins_pair_id ON kb_pool_origins(pair_id) "#, ) - .await + .await; } async fn create_kb_idx_pool_origins_listing_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_origins_listing_id", r#" @@ -1550,13 +1552,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_origins_listing_id ON kb_pool_origins(pool_listing_id) "#, ) - .await + .await; } async fn create_kb_idx_pool_origins_transaction_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pool_origins_transaction_id", r#" @@ -1564,11 +1566,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_pool_origins_transaction_id ON kb_pool_origins(founding_transaction_id) "#, ) - .await + .await; } async fn create_kb_wallets_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_wallets_table", r#" @@ -1581,13 +1583,13 @@ CREATE TABLE IF NOT EXISTS kb_wallets ( ) "#, ) - .await + .await; } async fn create_kb_wallet_participations_table( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_wallet_participations_table", r#" @@ -1612,13 +1614,13 @@ CREATE TABLE IF NOT EXISTS kb_wallet_participations ( ) "#, ) - .await + .await; } async fn create_kb_idx_wallet_participations_wallet_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_wallet_participations_wallet_id", r#" @@ -1626,13 +1628,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_wallet_participations_wallet_id ON kb_wallet_participations(wallet_id) "#, ) - .await + .await; } async fn create_kb_idx_wallet_participations_pool_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_wallet_participations_pool_id", r#" @@ -1640,13 +1642,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_wallet_participations_pool_id ON kb_wallet_participations(pool_id) "#, ) - .await + .await; } async fn create_kb_idx_wallet_participations_transaction_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_wallet_participations_transaction_id", r#" @@ -1654,11 +1656,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_wallet_participations_transaction_id ON kb_wallet_participations(transaction_id) "#, ) - .await + .await; } async fn create_kb_trade_events_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_trade_events_table", r#" @@ -1692,11 +1694,11 @@ CREATE TABLE IF NOT EXISTS kb_trade_events ( ) "#, ) - .await + .await; } async fn create_kb_idx_trade_events_pair_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_trade_events_pair_id", r#" @@ -1704,11 +1706,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_trade_events_pair_id ON kb_trade_events(pair_id) "#, ) - .await + .await; } async fn create_kb_idx_trade_events_pool_id(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_trade_events_pool_id", r#" @@ -1716,11 +1718,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_trade_events_pool_id ON kb_trade_events(pool_id) "#, ) - .await + .await; } async fn create_kb_pair_metrics_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pair_metrics_table", r#" @@ -1743,11 +1745,11 @@ CREATE TABLE IF NOT EXISTS kb_pair_metrics ( ) "#, ) - .await + .await; } async fn create_kb_wallet_holdings_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_wallet_holdings_table", r#" @@ -1778,13 +1780,13 @@ CREATE TABLE IF NOT EXISTS kb_wallet_holdings ( ) "#, ) - .await + .await; } async fn create_kb_idx_wallet_holdings_wallet_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_wallet_holdings_wallet_id", r#" @@ -1792,13 +1794,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_wallet_holdings_wallet_id ON kb_wallet_holdings(wallet_id) "#, ) - .await + .await; } async fn create_kb_idx_wallet_holdings_token_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_wallet_holdings_token_id", r#" @@ -1806,11 +1808,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_wallet_holdings_token_id ON kb_wallet_holdings(token_id) "#, ) - .await + .await; } async fn create_kb_pair_candles_table(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pair_candles_table", r#" @@ -1838,13 +1840,13 @@ CREATE TABLE IF NOT EXISTS kb_pair_candles ( ) "#, ) - .await + .await; } async fn create_kb_idx_pair_candles_pair_timeframe( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pair_candles_pair_timeframe", r#" @@ -1852,11 +1854,11 @@ CREATE INDEX IF NOT EXISTS kb_idx_pair_candles_pair_timeframe ON kb_pair_candles(pair_id, timeframe_seconds) "#, ) - .await + .await; } async fn create_kb_idx_pair_candles_bucket(pool: &sqlx::SqlitePool) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pair_candles_bucket", r#" @@ -1864,13 +1866,13 @@ CREATE INDEX IF NOT EXISTS kb_idx_pair_candles_bucket ON kb_pair_candles(bucket_start_unix) "#, ) - .await + .await; } async fn create_kb_pair_analytic_signals_table( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_pair_analytic_signals_table", r#" @@ -1894,13 +1896,13 @@ CREATE TABLE IF NOT EXISTS kb_pair_analytic_signals ( ) "#, ) - .await + .await; } async fn create_kb_idx_pair_analytic_signals_pair_id( pool: &sqlx::SqlitePool, ) -> Result<(), crate::KbError> { - execute_sqlite_schema_statement( + return execute_sqlite_schema_statement( pool, "create_kb_idx_pair_analytic_signals_pair_id", r#" @@ -1908,5 +1910,5 @@ CREATE INDEX IF NOT EXISTS kb_idx_pair_analytic_signals_pair_id ON kb_pair_analytic_signals(pair_id) "#, ) - .await + .await; } diff --git a/kb_lib/src/db/sqlite.rs b/kb_lib/src/db/sqlite.rs index 0bac4c6..a2c6f83 100644 --- a/kb_lib/src/db/sqlite.rs +++ b/kb_lib/src/db/sqlite.rs @@ -8,12 +8,10 @@ pub(crate) fn sqlite_database_url_from_config( ) -> Result { let path = config.sqlite.path.trim(); if path.is_empty() { - return Err(crate::KbError::Config( - "database.sqlite.path must not be empty".to_string(), - )); + return Err(crate::KbError::Config("database.sqlite.path must not be empty".to_string())); } let database_path = config.sqlite.path_buf(); - Ok(format!("sqlite://{}", database_path.display())) + return Ok(format!("sqlite://{}", database_path.display())); } /// Opens a SQLite pool according to configuration. @@ -22,9 +20,7 @@ pub(crate) async fn connect_sqlite( ) -> Result { let path = config.sqlite.path.trim(); if path.is_empty() { - return Err(crate::KbError::Config( - "database.sqlite.path must not be empty".to_string(), - )); + return Err(crate::KbError::Config("database.sqlite.path must not be empty".to_string())); } if config.sqlite.max_connections == 0 { return Err(crate::KbError::Config( @@ -49,9 +45,7 @@ pub(crate) async fn connect_sqlite( .filename(&database_path) .create_if_missing(config.sqlite.create_if_missing) .foreign_keys(true) - .busy_timeout(std::time::Duration::from_millis( - config.sqlite.busy_timeout_ms, - )); + .busy_timeout(std::time::Duration::from_millis(config.sqlite.busy_timeout_ms)); if config.sqlite.use_wal { connect_options = connect_options.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal); } @@ -59,10 +53,13 @@ pub(crate) async fn connect_sqlite( sqlx::sqlite::SqlitePoolOptions::new().max_connections(config.sqlite.max_connections); let connect_result = pool_options.connect_with(connect_options).await; match connect_result { - Ok(pool) => Ok(pool), - Err(error) => Err(crate::KbError::Db(format!( - "cannot open sqlite database '{}': {}", - database_path.display(), error - ))), + Ok(pool) => return Ok(pool), + Err(error) => { + return Err(crate::KbError::Db(format!( + "cannot open sqlite database '{}': {}", + database_path.display(), + error + ))); + }, } } diff --git a/kb_lib/src/db/types/analysis_signal_severity.rs b/kb_lib/src/db/types/analysis_signal_severity.rs index fb5422b..8a68c1e 100644 --- a/kb_lib/src/db/types/analysis_signal_severity.rs +++ b/kb_lib/src/db/types/analysis_signal_severity.rs @@ -21,28 +21,28 @@ impl KbAnalysisSignalSeverity { /// Converts the severity to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Info => 0, - Self::Low => 1, - Self::Medium => 2, - Self::High => 3, - Self::Critical => 4, + Self::Info => return 0, + Self::Low => return 1, + Self::Medium => return 2, + Self::High => return 3, + Self::Critical => return 4, } } /// Restores a severity from its stable integer representation. - pub fn from_i16( - value: i16, - ) -> Result { + pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Info), - 1 => Ok(Self::Low), - 2 => Ok(Self::Medium), - 3 => Ok(Self::High), - 4 => Ok(Self::Critical), - _ => Err(crate::KbError::Db(format!( - "invalid KbAnalysisSignalSeverity value: {}", - value - ))), + 0 => return Ok(Self::Info), + 1 => return Ok(Self::Low), + 2 => return Ok(Self::Medium), + 3 => return Ok(Self::High), + 4 => return Ok(Self::Critical), + _ => { + return Err(crate::KbError::Db(format!( + "invalid KbAnalysisSignalSeverity value: {}", + value + ))); + }, } } } diff --git a/kb_lib/src/db/types/liquidity_event_kind.rs b/kb_lib/src/db/types/liquidity_event_kind.rs index 1671590..598416b 100644 --- a/kb_lib/src/db/types/liquidity_event_kind.rs +++ b/kb_lib/src/db/types/liquidity_event_kind.rs @@ -15,20 +15,22 @@ impl KbLiquidityEventKind { /// Converts the event kind to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Add => 0, - Self::Remove => 1, + Self::Add => return 0, + Self::Remove => return 1, } } /// Restores an event kind from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Add), - 1 => Ok(Self::Remove), - _ => Err(crate::KbError::Db(format!( - "invalid KbLiquidityEventKind value: {}", - value - ))), + 0 => return Ok(Self::Add), + 1 => return Ok(Self::Remove), + _ => { + return Err(crate::KbError::Db(format!( + "invalid KbLiquidityEventKind value: {}", + value + ))); + }, } } } diff --git a/kb_lib/src/db/types/observation_source_kind.rs b/kb_lib/src/db/types/observation_source_kind.rs index e14b974..2a06101 100644 --- a/kb_lib/src/db/types/observation_source_kind.rs +++ b/kb_lib/src/db/types/observation_source_kind.rs @@ -21,26 +21,28 @@ impl KbObservationSourceKind { /// Converts the source kind to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::HttpRpc => 0, - Self::WsRpc => 1, - Self::Grpc => 2, - Self::Dex => 3, - Self::Other => 4, + Self::HttpRpc => return 0, + Self::WsRpc => return 1, + Self::Grpc => return 2, + Self::Dex => return 3, + Self::Other => return 4, } } /// Restores a source kind from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::HttpRpc), - 1 => Ok(Self::WsRpc), - 2 => Ok(Self::Grpc), - 3 => Ok(Self::Dex), - 4 => Ok(Self::Other), - _ => Err(crate::KbError::Db(format!( - "invalid KbObservationSourceKind value: {}", - value - ))), + 0 => return Ok(Self::HttpRpc), + 1 => return Ok(Self::WsRpc), + 2 => return Ok(Self::Grpc), + 3 => return Ok(Self::Dex), + 4 => return Ok(Self::Other), + _ => { + return Err(crate::KbError::Db(format!( + "invalid KbObservationSourceKind value: {}", + value + ))); + }, } } } diff --git a/kb_lib/src/db/types/observed_token_status.rs b/kb_lib/src/db/types/observed_token_status.rs index faeac6d..97c8b6a 100644 --- a/kb_lib/src/db/types/observed_token_status.rs +++ b/kb_lib/src/db/types/observed_token_status.rs @@ -19,24 +19,26 @@ impl KbObservedTokenStatus { /// Converts the status to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::New => 0, - Self::Active => 1, - Self::Ignored => 2, - Self::Blocked => 3, + Self::New => return 0, + Self::Active => return 1, + Self::Ignored => return 2, + Self::Blocked => return 3, } } /// Restores a status from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::New), - 1 => Ok(Self::Active), - 2 => Ok(Self::Ignored), - 3 => Ok(Self::Blocked), - _ => Err(crate::KbError::Db(format!( - "invalid KbObservedTokenStatus value: {}", - value - ))), + 0 => return Ok(Self::New), + 1 => return Ok(Self::Active), + 2 => return Ok(Self::Ignored), + 3 => return Ok(Self::Blocked), + _ => { + return Err(crate::KbError::Db(format!( + "invalid KbObservedTokenStatus value: {}", + value + ))); + }, } } } diff --git a/kb_lib/src/db/types/pool_kind.rs b/kb_lib/src/db/types/pool_kind.rs index efc4797..42e617e 100644 --- a/kb_lib/src/db/types/pool_kind.rs +++ b/kb_lib/src/db/types/pool_kind.rs @@ -1,4 +1,3 @@ - // file: kb_lib/src/db/types/pool_kind.rs //! Pool kind. @@ -22,28 +21,23 @@ impl KbPoolKind { /// Converts the kind to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Unknown => 0, - Self::Amm => 1, - Self::Clmm => 2, - Self::BondingCurve => 3, - Self::OrderBook => 4, + Self::Unknown => return 0, + Self::Amm => return 1, + Self::Clmm => return 2, + Self::BondingCurve => return 3, + Self::OrderBook => return 4, } } /// Restores a kind from its stable integer representation. - pub fn from_i16( - value: i16, - ) -> Result { + pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Unknown), - 1 => Ok(Self::Amm), - 2 => Ok(Self::Clmm), - 3 => Ok(Self::BondingCurve), - 4 => Ok(Self::OrderBook), - _ => Err(crate::KbError::Db(format!( - "invalid KbPoolKind value: {}", - value - ))), + 0 => return Ok(Self::Unknown), + 1 => return Ok(Self::Amm), + 2 => return Ok(Self::Clmm), + 3 => return Ok(Self::BondingCurve), + 4 => return Ok(Self::OrderBook), + _ => return Err(crate::KbError::Db(format!("invalid KbPoolKind value: {}", value))), } } } diff --git a/kb_lib/src/db/types/pool_status.rs b/kb_lib/src/db/types/pool_status.rs index cab2be0..8f675bb 100644 --- a/kb_lib/src/db/types/pool_status.rs +++ b/kb_lib/src/db/types/pool_status.rs @@ -21,26 +21,23 @@ impl KbPoolStatus { /// Converts the status to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Unknown => 0, - Self::Pending => 1, - Self::Active => 2, - Self::Inactive => 3, - Self::Closed => 4, + Self::Unknown => return 0, + Self::Pending => return 1, + Self::Active => return 2, + Self::Inactive => return 3, + Self::Closed => return 4, } } /// Restores a status from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Unknown), - 1 => Ok(Self::Pending), - 2 => Ok(Self::Active), - 3 => Ok(Self::Inactive), - 4 => Ok(Self::Closed), - _ => Err(crate::KbError::Db(format!( - "invalid KbPoolStatus value: {}", - value - ))), + 0 => return Ok(Self::Unknown), + 1 => return Ok(Self::Pending), + 2 => return Ok(Self::Active), + 3 => return Ok(Self::Inactive), + 4 => return Ok(Self::Closed), + _ => return Err(crate::KbError::Db(format!("invalid KbPoolStatus value: {}", value))), } } } diff --git a/kb_lib/src/db/types/pool_token_role.rs b/kb_lib/src/db/types/pool_token_role.rs index 362acd4..0a7b409 100644 --- a/kb_lib/src/db/types/pool_token_role.rs +++ b/kb_lib/src/db/types/pool_token_role.rs @@ -21,26 +21,25 @@ impl KbPoolTokenRole { /// Converts the role to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Base => 0, - Self::Quote => 1, - Self::LpMint => 2, - Self::Reserve => 3, - Self::Other => 4, + Self::Base => return 0, + Self::Quote => return 1, + Self::LpMint => return 2, + Self::Reserve => return 3, + Self::Other => return 4, } } /// Restores a role from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Base), - 1 => Ok(Self::Quote), - 2 => Ok(Self::LpMint), - 3 => Ok(Self::Reserve), - 4 => Ok(Self::Other), - _ => Err(crate::KbError::Db(format!( - "invalid KbPoolTokenRole value: {}", - value - ))), + 0 => return Ok(Self::Base), + 1 => return Ok(Self::Quote), + 2 => return Ok(Self::LpMint), + 3 => return Ok(Self::Reserve), + 4 => return Ok(Self::Other), + _ => { + return Err(crate::KbError::Db(format!("invalid KbPoolTokenRole value: {}", value))); + }, } } } diff --git a/kb_lib/src/db/types/runtime_event_level.rs b/kb_lib/src/db/types/runtime_event_level.rs index f72aa85..bb65403 100644 --- a/kb_lib/src/db/types/runtime_event_level.rs +++ b/kb_lib/src/db/types/runtime_event_level.rs @@ -21,26 +21,28 @@ impl KbDbRuntimeEventLevel { /// Converts the level to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Trace => 0, - Self::Debug => 1, - Self::Info => 2, - Self::Warn => 3, - Self::Error => 4, + Self::Trace => return 0, + Self::Debug => return 1, + Self::Info => return 2, + Self::Warn => return 3, + Self::Error => return 4, } } /// Restores a level from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Trace), - 1 => Ok(Self::Debug), - 2 => Ok(Self::Info), - 3 => Ok(Self::Warn), - 4 => Ok(Self::Error), - _ => Err(crate::KbError::Db(format!( - "invalid KbDbRuntimeEventLevel value: {}", - value - ))), + 0 => return Ok(Self::Trace), + 1 => return Ok(Self::Debug), + 2 => return Ok(Self::Info), + 3 => return Ok(Self::Warn), + 4 => return Ok(Self::Error), + _ => { + return Err(crate::KbError::Db(format!( + "invalid KbDbRuntimeEventLevel value: {}", + value + ))); + }, } } } diff --git a/kb_lib/src/db/types/swap_trade_side.rs b/kb_lib/src/db/types/swap_trade_side.rs index 084dde6..4956d80 100644 --- a/kb_lib/src/db/types/swap_trade_side.rs +++ b/kb_lib/src/db/types/swap_trade_side.rs @@ -17,22 +17,24 @@ impl KbSwapTradeSide { /// Converts the trade side to its stable integer representation. pub fn to_i16(self) -> i16 { match self { - Self::Unknown => 0, - Self::BuyBase => 1, - Self::SellBase => 2, + Self::Unknown => return 0, + Self::BuyBase => return 1, + Self::SellBase => return 2, } } /// Restores a trade side from its stable integer representation. pub fn from_i16(value: i16) -> Result { match value { - 0 => Ok(Self::Unknown), - 1 => Ok(Self::BuyBase), - 2 => Ok(Self::SellBase), - _ => Err(crate::KbError::Db(format!( - "invalid KbSwapTradeSide value: {}", - value - ))), + 0 => return Ok(Self::Unknown), + 1 => return Ok(Self::BuyBase), + 2 => return Ok(Self::SellBase), + _ => { + return Err(crate::KbError::Db(format!( + "invalid KbSwapTradeSide value: {}", + value + ))); + }, } } } diff --git a/kb_lib/src/detect/service.rs b/kb_lib/src/detect/service.rs index f14298a..de3d6a0 100644 --- a/kb_lib/src/detect/service.rs +++ b/kb_lib/src/detect/service.rs @@ -12,11 +12,11 @@ pub struct KbDetectionPersistenceService { impl KbDetectionPersistenceService { /// Creates a new detection persistence service. pub fn new(database: std::sync::Arc) -> Self { - Self { database } + return Self { database }; } /// Returns the shared database handle. pub fn database(&self) -> &std::sync::Arc { - &self.database + return &self.database; } /// Persists one on-chain observation. @@ -32,7 +32,7 @@ impl KbDetectionPersistenceService { input.slot, input.payload.clone(), ); - crate::insert_onchain_observation(self.database.as_ref(), &dto).await + return crate::insert_onchain_observation(self.database.as_ref(), &dto).await; } /// Persists one analysis signal. @@ -48,7 +48,7 @@ impl KbDetectionPersistenceService { input.score, input.payload.clone(), ); - crate::insert_analysis_signal(self.database.as_ref(), &dto).await + return crate::insert_analysis_signal(self.database.as_ref(), &dto).await; } /// Registers one token candidate from a technical source. @@ -104,11 +104,7 @@ impl KbDetectionPersistenceService { Ok(signal_id) => signal_id, Err(error) => return Err(error), }; - Ok(crate::KbDetectionTokenCandidateResult { - token_id, - observation_id, - signal_id, - }) + return Ok(crate::KbDetectionTokenCandidateResult { token_id, observation_id, signal_id }); } /// Registers one pool candidate from a technical source. @@ -154,7 +150,7 @@ impl KbDetectionPersistenceService { "cannot register pool candidate: no known dex matches program id '{}'", input.dex_program_id ))); - } + }, }; let dex_id = match matched_dex.id { Some(dex_id) => dex_id, @@ -162,7 +158,7 @@ impl KbDetectionPersistenceService { return Err(crate::KbError::Db( "cannot register pool candidate: matched dex has no id".to_string(), )); - } + }, }; let pool_dto = crate::KbPoolDto::new( dex_id, @@ -221,13 +217,13 @@ impl KbDetectionPersistenceService { Ok(signal_id) => signal_id, Err(error) => return Err(error), }; - Ok(crate::KbDetectionPoolCandidateResult { + return Ok(crate::KbDetectionPoolCandidateResult { dex_id, pool_id, pool_listing_id, observation_id, signal_id, - }) + }); } } @@ -248,9 +244,9 @@ mod tests { use_wal: true, }, }; - crate::KbDatabase::connect_and_initialize(&config) + return crate::KbDatabase::connect_and_initialize(&config) .await - .expect("database init must succeed") + .expect("database init must succeed"); } #[tokio::test] @@ -293,14 +289,8 @@ mod tests { .expect("list signals must succeed"); assert_eq!(observations.len(), 1); assert_eq!(signals.len(), 1); - assert_eq!( - observations[0].object_key, - "So11111111111111111111111111111111111111112" - ); - assert_eq!( - signals[0].object_key, - "So11111111111111111111111111111111111111112" - ); + assert_eq!(observations[0].object_key, "So11111111111111111111111111111111111111112"); + assert_eq!(signals[0].object_key, "So11111111111111111111111111111111111111112"); } #[tokio::test] @@ -340,10 +330,7 @@ mod tests { .await .expect("get token must succeed"); assert!(token.is_some()); - assert_eq!( - token.expect("token must exist").symbol.as_deref(), - Some("TEST") - ); + assert_eq!(token.expect("token must exist").symbol.as_deref(), Some("TEST")); let observations = crate::list_recent_onchain_observations(service.database().as_ref(), 10) .await .expect("list observations must succeed"); @@ -352,18 +339,9 @@ mod tests { .expect("list signals must succeed"); assert_eq!(observations.len(), 1); assert_eq!(signals.len(), 1); - assert_eq!( - observations[0].object_key, - "Mint111111111111111111111111111111111111111" - ); - assert_eq!( - signals[0].object_key, - "Mint111111111111111111111111111111111111111" - ); - assert_eq!( - signals[0].related_observation_id, - Some(result.observation_id) - ); + assert_eq!(observations[0].object_key, "Mint111111111111111111111111111111111111111"); + assert_eq!(signals[0].object_key, "Mint111111111111111111111111111111111111111"); + assert_eq!(signals[0].related_observation_id, Some(result.observation_id)); } #[tokio::test] diff --git a/kb_lib/src/detect/solana_ws.rs b/kb_lib/src/detect/solana_ws.rs index 959da6a..9d932fe 100644 --- a/kb_lib/src/detect/solana_ws.rs +++ b/kb_lib/src/detect/solana_ws.rs @@ -37,12 +37,12 @@ pub struct KbSolanaWsDetectionService { impl KbSolanaWsDetectionService { /// Creates a new Solana WebSocket detection service. pub fn new(persistence: crate::KbDetectionPersistenceService) -> Self { - Self { persistence } + return Self { persistence }; } /// Returns the shared persistence façade. pub fn persistence(&self) -> &crate::KbDetectionPersistenceService { - &self.persistence + return &self.persistence; } /// Processes one Solana WebSocket JSON-RPC notification. @@ -57,24 +57,22 @@ impl KbSolanaWsDetectionService { Some(observation_kind) => observation_kind, None => return Ok(crate::KbSolanaWsDetectionOutcome::Ignored), }; - let token_candidate_result = self - .try_register_token_candidate(endpoint_name.clone(), notification) - .await; + let token_candidate_result = + self.try_register_token_candidate(endpoint_name.clone(), notification).await; match token_candidate_result { Ok(Some(result)) => { return Ok(crate::KbSolanaWsDetectionOutcome::TokenCandidateRegistered { result }); - } - Ok(None) => {} + }, + Ok(None) => {}, Err(error) => return Err(error), } - let pool_candidate_result = self - .try_register_pool_candidate(endpoint_name.clone(), notification) - .await; + let pool_candidate_result = + self.try_register_pool_candidate(endpoint_name.clone(), notification).await; match pool_candidate_result { Ok(Some(result)) => { return Ok(crate::KbSolanaWsDetectionOutcome::PoolCandidateRegistered { result }); - } - Ok(None) => {} + }, + Ok(None) => {}, Err(error) => return Err(error), } let payload = build_notification_payload(notification); @@ -93,10 +91,7 @@ impl KbSolanaWsDetectionService { slot, payload.clone(), ); - let observation_id_result = self - .persistence - .record_observation(&observation_input) - .await; + let observation_id_result = self.persistence.record_observation(&observation_input).await; let observation_id = match observation_id_result { Ok(observation_id) => observation_id, Err(error) => return Err(error), @@ -127,7 +122,7 @@ impl KbSolanaWsDetectionService { return Err(error); } } - Ok(crate::KbSolanaWsDetectionOutcome::ObservationRecorded { observation_id }) + return Ok(crate::KbSolanaWsDetectionOutcome::ObservationRecorded { observation_id }); } /// Tries to register a token candidate from one notification. @@ -210,8 +205,8 @@ impl KbSolanaWsDetectionService { ); let result = self.persistence.register_token_candidate(&input).await; match result { - Ok(result) => Ok(Some(result)), - Err(error) => Err(error), + Ok(result) => return Ok(Some(result)), + Err(error) => return Err(error), } } @@ -288,8 +283,8 @@ impl KbSolanaWsDetectionService { ); let result = self.persistence.register_pool_candidate(&input).await; match result { - Ok(result) => Ok(Some(result)), - Err(error) => Err(error), + Ok(result) => return Ok(Some(result)), + Err(error) => return Err(error), } } } @@ -299,27 +294,27 @@ fn map_notification_method_to_observation_kind( method: &str, ) -> std::option::Option { match method { - "accountNotification" => Some("ws.account_notification".to_string()), - "blockNotification" => Some("ws.block_notification".to_string()), - "logsNotification" => Some("ws.logs_notification".to_string()), - "programNotification" => Some("ws.program_notification".to_string()), - "rootNotification" => Some("ws.root_notification".to_string()), - "signatureNotification" => Some("ws.signature_notification".to_string()), - "slotNotification" => Some("ws.slot_notification".to_string()), - "slotsUpdatesNotification" => Some("ws.slots_updates_notification".to_string()), - "voteNotification" => Some("ws.vote_notification".to_string()), - _ => None, + "accountNotification" => return Some("ws.account_notification".to_string()), + "blockNotification" => return Some("ws.block_notification".to_string()), + "logsNotification" => return Some("ws.logs_notification".to_string()), + "programNotification" => return Some("ws.program_notification".to_string()), + "rootNotification" => return Some("ws.root_notification".to_string()), + "signatureNotification" => return Some("ws.signature_notification".to_string()), + "slotNotification" => return Some("ws.slot_notification".to_string()), + "slotsUpdatesNotification" => return Some("ws.slots_updates_notification".to_string()), + "voteNotification" => return Some("ws.vote_notification".to_string()), + _ => return None, } } /// Wraps one raw notification into a normalized JSON payload. fn build_notification_payload(notification: &crate::KbJsonRpcWsNotification) -> serde_json::Value { - serde_json::json!({ + return serde_json::json!({ "jsonrpc": notification.jsonrpc, "method": notification.method, "subscription": notification.params.subscription, "result": notification.params.result, - }) + }); } /// Builds one logical object key from the notification result. @@ -340,8 +335,7 @@ fn build_object_key( if let Some(slot) = slot_option { return format!("slot:{slot}"); } - - format!("subscription:{subscription}") + return format!("subscription:{subscription}"); } /// Extracts a slot number from one notification result. @@ -364,7 +358,7 @@ fn extract_slot_from_result(method: &str, result: &serde_json::Value) -> std::op return Some(slot); } } - None + return None; } /// Extracts a pubkey from one notification result. @@ -379,7 +373,7 @@ fn extract_pubkey_from_result( return Some(pubkey.to_string()); } } - None + return None; } /// Extracts a signature from one notification result. @@ -394,13 +388,13 @@ fn extract_signature_from_result( return Some(signature.to_string()); } } - None + return None; } /// Extracts one account-like JSON object from one notification result. -fn extract_account_value_from_result<'a>( - result: &'a serde_json::Value, -) -> std::option::Option<&'a serde_json::Value> { +fn extract_account_value_from_result( + result: &serde_json::Value, +) -> std::option::Option<&serde_json::Value> { if let Some(account) = result.get("account") { return Some(account); } @@ -412,7 +406,7 @@ fn extract_account_value_from_result<'a>( return Some(value); } } - None + return None; } /// Extracts the parsed account type from one account-like JSON object. @@ -431,8 +425,8 @@ fn extract_parsed_account_type( }; let type_option = parsed.get("type").and_then(serde_json::Value::as_str); match type_option { - Some(parsed_type) => Some(parsed_type.to_string()), - None => None, + Some(parsed_type) => return Some(parsed_type.to_string()), + None => return None, } } @@ -440,12 +434,10 @@ fn extract_parsed_account_type( fn extract_account_owner( account_value: &serde_json::Value, ) -> std::option::Option { - let owner_option = account_value - .get("owner") - .and_then(serde_json::Value::as_str); + let owner_option = account_value.get("owner").and_then(serde_json::Value::as_str); match owner_option { - Some(owner) => Some(owner.to_string()), - None => None, + Some(owner) => return Some(owner.to_string()), + None => return None, } } @@ -475,8 +467,8 @@ fn extract_decimals_from_account_value( }; let converted = u8::try_from(decimals); match converted { - Ok(decimals) => Some(decimals), - Err(_) => None, + Ok(decimals) => return Some(decimals), + Err(_) => return None, } } @@ -489,7 +481,7 @@ fn extract_program_notification_owner( Some(account_value) => account_value, None => return None, }; - extract_account_owner(account_value) + return extract_account_owner(account_value); } /// Extracts the parsed token amount decimals from one parsed token account notification. @@ -516,17 +508,15 @@ fn extract_token_account_decimals_from_account_value( Some(token_amount) => token_amount, None => return None, }; - let decimals_option = token_amount - .get("decimals") - .and_then(serde_json::Value::as_u64); + let decimals_option = token_amount.get("decimals").and_then(serde_json::Value::as_u64); let decimals = match decimals_option { Some(decimals) => decimals, None => return None, }; let convert_result = u8::try_from(decimals); match convert_result { - Ok(decimals) => Some(decimals), - Err(_) => None, + Ok(decimals) => return Some(decimals), + Err(_) => return None, } } @@ -551,8 +541,8 @@ fn extract_parsed_account_mint( }; let mint_option = info.get("mint").and_then(serde_json::Value::as_str); match mint_option { - Some(mint) => Some(mint.to_string()), - None => None, + Some(mint) => return Some(mint.to_string()), + None => return None, } } @@ -580,7 +570,7 @@ fn extract_logs_lines(result: &serde_json::Value) -> std::vec::Vec return None, }; match value.get("err") { - Some(err) => Some(err.clone()), - None => None, + Some(err) => return Some(err.clone()), + None => return None, } } @@ -621,8 +611,8 @@ fn build_signal_kind_for_notification( } } } - "signal.account_notification.generic".to_string() - } + return "signal.account_notification.generic".to_string(); + }, "logsNotification" => { let lines = extract_logs_lines(result); for line in &lines { @@ -639,21 +629,21 @@ fn build_signal_kind_for_notification( return "signal.logs_notification.initialize_account".to_string(); } } - "signal.logs_notification.generic".to_string() - } + return "signal.logs_notification.generic".to_string(); + }, "signatureNotification" => { let err_option = extract_signature_notification_err(result); match err_option { Some(err) => { if err.is_null() { - "signal.signature_notification.confirmed".to_string() + return "signal.signature_notification.confirmed".to_string(); } else { - "signal.signature_notification.failed".to_string() + return "signal.signature_notification.failed".to_string(); } - } - None => "signal.signature_notification.generic".to_string(), + }, + None => return "signal.signature_notification.generic".to_string(), } - } + }, "programNotification" => { let owner_option = extract_program_notification_owner(result); let owner = match owner_option { @@ -666,12 +656,9 @@ fn build_signal_kind_for_notification( if owner == crate::SPL_TOKEN_2022_PROGRAM_ID.to_string() { return "signal.program_notification.spl_token_2022".to_string(); } - "signal.program_notification.generic".to_string() - } - _ => format!( - "signal.{}", - method.replace("Notification", "").to_lowercase() - ), + return "signal.program_notification.generic".to_string(); + }, + _ => return format!("signal.{}", method.replace("Notification", "").to_lowercase()), } } @@ -681,8 +668,8 @@ fn build_signal_severity_for_notification( result: &serde_json::Value, ) -> crate::KbAnalysisSignalSeverity { match method { - "programNotification" => crate::KbAnalysisSignalSeverity::Medium, - "accountNotification" => crate::KbAnalysisSignalSeverity::Low, + "programNotification" => return crate::KbAnalysisSignalSeverity::Medium, + "accountNotification" => return crate::KbAnalysisSignalSeverity::Low, "logsNotification" => { let lines = extract_logs_lines(result); for line in &lines { @@ -690,22 +677,22 @@ fn build_signal_severity_for_notification( return crate::KbAnalysisSignalSeverity::Medium; } } - crate::KbAnalysisSignalSeverity::Low - } + return crate::KbAnalysisSignalSeverity::Low; + }, "signatureNotification" => { let err_option = extract_signature_notification_err(result); match err_option { Some(err) => { if err.is_null() { - crate::KbAnalysisSignalSeverity::Low + return crate::KbAnalysisSignalSeverity::Low; } else { - crate::KbAnalysisSignalSeverity::Medium + return crate::KbAnalysisSignalSeverity::Medium; } - } - None => crate::KbAnalysisSignalSeverity::Low, + }, + None => return crate::KbAnalysisSignalSeverity::Low, } - } - _ => crate::KbAnalysisSignalSeverity::Low, + }, + _ => return crate::KbAnalysisSignalSeverity::Low, } } @@ -726,13 +713,13 @@ mod tests { use_wal: true, }, }; - crate::KbDatabase::connect_and_initialize(&config) + return crate::KbDatabase::connect_and_initialize(&config) .await - .expect("database init must succeed") + .expect("database init must succeed"); } fn build_slot_notification() -> crate::KbJsonRpcWsNotification { - crate::KbJsonRpcWsNotification { + return crate::KbJsonRpcWsNotification { jsonrpc: "2.0".to_string(), method: "slotNotification".to_string(), params: crate::KbJsonRpcWsNotificationParams { @@ -743,11 +730,11 @@ mod tests { }), subscription: 1008_u64, }, - } + }; } fn build_program_mint_notification() -> crate::KbJsonRpcWsNotification { - crate::KbJsonRpcWsNotification { + return crate::KbJsonRpcWsNotification { jsonrpc: "2.0".to_string(), method: "programNotification".to_string(), params: crate::KbJsonRpcWsNotificationParams { @@ -773,11 +760,11 @@ mod tests { }), subscription: 2048_u64, }, - } + }; } fn build_program_pool_candidate_notification() -> crate::KbJsonRpcWsNotification { - crate::KbJsonRpcWsNotification { + return crate::KbJsonRpcWsNotification { jsonrpc: "2.0".to_string(), method: "programNotification".to_string(), params: crate::KbJsonRpcWsNotificationParams { @@ -798,11 +785,11 @@ mod tests { }), subscription: 5555_u64, }, - } + }; } fn build_logs_notification() -> crate::KbJsonRpcWsNotification { - crate::KbJsonRpcWsNotification { + return crate::KbJsonRpcWsNotification { jsonrpc: "2.0".to_string(), method: "logsNotification".to_string(), params: crate::KbJsonRpcWsNotificationParams { @@ -820,11 +807,11 @@ mod tests { }), subscription: 3001_u64, }, - } + }; } fn build_signature_notification() -> crate::KbJsonRpcWsNotification { - crate::KbJsonRpcWsNotification { + return crate::KbJsonRpcWsNotification { jsonrpc: "2.0".to_string(), method: "signatureNotification".to_string(), params: crate::KbJsonRpcWsNotificationParams { @@ -838,7 +825,7 @@ mod tests { }), subscription: 4001_u64, }, - } + }; } #[tokio::test] @@ -859,7 +846,7 @@ mod tests { match outcome { crate::KbSolanaWsDetectionOutcome::ObservationRecorded { observation_id } => { assert!(observation_id > 0); - } + }, _ => panic!("unexpected detection outcome"), } let observations_result = @@ -894,7 +881,7 @@ mod tests { assert!(result.token_id > 0); assert!(result.observation_id > 0); assert!(result.signal_id > 0); - } + }, _ => panic!("unexpected detection outcome"), } let token_result = crate::get_token_by_mint( @@ -923,14 +910,8 @@ mod tests { }; assert_eq!(observations.len(), 1); assert_eq!(signals.len(), 1); - assert_eq!( - observations[0].object_key, - "Mint111111111111111111111111111111111111111" - ); - assert_eq!( - signals[0].object_key, - "Mint111111111111111111111111111111111111111" - ); + assert_eq!(observations[0].object_key, "Mint111111111111111111111111111111111111111"); + assert_eq!(signals[0].object_key, "Mint111111111111111111111111111111111111111"); } #[tokio::test] @@ -951,7 +932,7 @@ mod tests { match outcome { crate::KbSolanaWsDetectionOutcome::ObservationRecorded { observation_id } => { assert!(observation_id > 0); - } + }, _ => panic!("unexpected detection outcome"), } let observations_result = @@ -970,10 +951,7 @@ mod tests { }; assert_eq!(observations.len(), 1); assert_eq!(signals.len(), 1); - assert_eq!( - signals[0].signal_kind, - "signal.logs_notification.initialize_mint" - ); + assert_eq!(signals[0].signal_kind, "signal.logs_notification.initialize_mint"); } #[tokio::test] @@ -994,7 +972,7 @@ mod tests { match outcome { crate::KbSolanaWsDetectionOutcome::ObservationRecorded { observation_id } => { assert!(observation_id > 0); - } + }, _ => panic!("unexpected detection outcome"), } let observations_result = @@ -1013,10 +991,7 @@ mod tests { }; assert_eq!(observations.len(), 1); assert_eq!(signals.len(), 1); - assert_eq!( - signals[0].signal_kind, - "signal.signature_notification.confirmed" - ); + assert_eq!(signals[0].signal_kind, "signal.signature_notification.confirmed"); } #[tokio::test] @@ -1053,7 +1028,7 @@ mod tests { assert!(result.pool_id > 0); assert!(result.pool_listing_id > 0); result.pool_id - } + }, _ => panic!("unexpected detection outcome"), }; let pool_result = crate::get_pool_by_address( diff --git a/kb_lib/src/detect/types.rs b/kb_lib/src/detect/types.rs index 52c7df2..6908c7d 100644 --- a/kb_lib/src/detect/types.rs +++ b/kb_lib/src/detect/types.rs @@ -29,14 +29,14 @@ impl KbDetectionObservationInput { slot: std::option::Option, payload: serde_json::Value, ) -> Self { - Self { + return Self { observation_kind, source_kind, endpoint_name, object_key, slot, payload, - } + }; } } @@ -67,14 +67,14 @@ impl KbDetectionSignalInput { score: std::option::Option, payload: serde_json::Value, ) -> Self { - Self { + return Self { signal_kind, severity, object_key, related_observation_id, score, payload, - } + }; } } @@ -133,7 +133,7 @@ impl KbDetectionTokenCandidateInput { signal_score: std::option::Option, signal_payload: std::option::Option, ) -> Self { - Self { + return Self { mint, symbol, name, @@ -149,7 +149,7 @@ impl KbDetectionTokenCandidateInput { signal_severity, signal_score, signal_payload, - } + }; } } @@ -207,7 +207,7 @@ impl KbDetectionPoolCandidateInput { signal_score: std::option::Option, signal_payload: std::option::Option, ) -> Self { - Self { + return Self { pool_address, dex_program_id, source_kind, @@ -219,7 +219,7 @@ impl KbDetectionPoolCandidateInput { signal_severity, signal_score, signal_payload, - } + }; } } diff --git a/kb_lib/src/detect/ws_relay.rs b/kb_lib/src/detect/ws_relay.rs index fcffa81..040a70d 100644 --- a/kb_lib/src/detect/ws_relay.rs +++ b/kb_lib/src/detect/ws_relay.rs @@ -20,10 +20,7 @@ impl KbWsDetectionNotificationEnvelope { endpoint_name: std::option::Option, notification: crate::KbJsonRpcWsNotification, ) -> Self { - Self { - endpoint_name, - notification, - } + return Self { endpoint_name, notification }; } } @@ -54,7 +51,7 @@ pub struct KbWsDetectionRelay { impl KbWsDetectionRelay { /// Creates a new relay. pub fn new(detector: crate::KbSolanaWsDetectionService) -> Self { - Self { detector } + return Self { detector }; } /// Creates a bounded relay channel. @@ -64,7 +61,7 @@ impl KbWsDetectionRelay { tokio::sync::mpsc::Sender, tokio::sync::mpsc::Receiver, ) { - tokio::sync::mpsc::channel(capacity) + return tokio::sync::mpsc::channel(capacity); } /// Processes one forwarded notification. @@ -72,9 +69,10 @@ impl KbWsDetectionRelay { &self, envelope: &crate::KbWsDetectionNotificationEnvelope, ) -> Result { - self.detector + return self + .detector .process_notification(envelope.endpoint_name.clone(), &envelope.notification) - .await + .await; } /// Spawns one background relay worker. @@ -82,7 +80,7 @@ impl KbWsDetectionRelay { self, mut receiver: tokio::sync::mpsc::Receiver, ) -> tokio::task::JoinHandle { - tokio::spawn(async move { + return tokio::spawn(async move { let mut stats = crate::KbWsDetectionRelayStats::default(); loop { let recv_result = receiver.recv().await; @@ -103,25 +101,25 @@ impl KbWsDetectionRelay { error ); continue; - } + }, }; match outcome { crate::KbSolanaWsDetectionOutcome::Ignored => { stats.ignored_count += 1; - } + }, crate::KbSolanaWsDetectionOutcome::ObservationRecorded { .. } => { stats.observation_count += 1; - } + }, crate::KbSolanaWsDetectionOutcome::TokenCandidateRegistered { .. } => { stats.token_candidate_count += 1; - } + }, crate::KbSolanaWsDetectionOutcome::PoolCandidateRegistered { .. } => { stats.pool_candidate_count += 1; - } + }, } } - stats - }) + return stats; + }); } } @@ -142,13 +140,13 @@ mod tests { use_wal: true, }, }; - crate::KbDatabase::connect_and_initialize(&config) + return crate::KbDatabase::connect_and_initialize(&config) .await - .expect("database init must succeed") + .expect("database init must succeed"); } fn build_slot_notification() -> crate::KbJsonRpcWsNotification { - crate::KbJsonRpcWsNotification { + return crate::KbJsonRpcWsNotification { jsonrpc: "2.0".to_string(), method: "slotNotification".to_string(), params: crate::KbJsonRpcWsNotificationParams { @@ -159,7 +157,7 @@ mod tests { }), subscription: 1008_u64, }, - } + }; } #[tokio::test] @@ -180,7 +178,7 @@ mod tests { match outcome { crate::KbSolanaWsDetectionOutcome::ObservationRecorded { observation_id } => { assert!(observation_id > 0); - } + }, _ => panic!("unexpected relay outcome"), } } diff --git a/kb_lib/src/dex/dexlab.rs b/kb_lib/src/dex/dexlab.rs index 13f21f7..e748a53 100644 --- a/kb_lib/src/dex/dexlab.rs +++ b/kb_lib/src/dex/dexlab.rs @@ -76,7 +76,7 @@ enum KbDexlabInstructionKind { impl KbDexlabDecoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more DexLab events. @@ -93,7 +93,7 @@ impl KbDexlabDecoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -104,7 +104,7 @@ impl KbDexlabDecoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -140,45 +140,24 @@ impl KbDexlabDecoder { kb_classify_instruction_kind(parsed_json.as_ref(), &log_messages); let pool_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "pool", - "poolAddress", - "poolAccount", - "amm", - "ammPool", - "poolState", - ], + &["pool", "poolAddress", "poolAccount", "amm", "ammPool", "poolState"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenA", - "tokenAMint", - "mintA", - "baseMint", - "token0Mint", - "mint0", - ], + &["tokenA", "tokenAMint", "mintA", "baseMint", "token0Mint", "mint0"], ) - .or_else(|| kb_extract_account(&accounts, 1)); + .or_else(|| return kb_extract_account(&accounts, 1)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenB", - "tokenBMint", - "mintB", - "quoteMint", - "token1Mint", - "mint1", - ], + &["tokenB", "tokenBMint", "mintB", "quoteMint", "token1Mint", "mint1"], ) - .or_else(|| kb_extract_account(&accounts, 2)); + .or_else(|| return kb_extract_account(&accounts, 2)); let creator = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["payer", "creator", "user", "owner"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let fee_tier = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["feeTier", "fee_tier", "tradeFeeTier", "feeRate"], @@ -246,7 +225,7 @@ impl KbDexlabDecoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -278,7 +257,7 @@ fn kb_classify_instruction_kind( if kb_log_messages_contain_keyword(log_messages, "swap") { return KbDexlabInstructionKind::Swap; } - KbDexlabInstructionKind::Unknown + return KbDexlabInstructionKind::Unknown; } fn kb_extract_log_messages( @@ -305,7 +284,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -316,7 +295,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_normalize_text(value: &str) -> std::string::String { @@ -326,7 +305,7 @@ fn kb_normalize_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } fn kb_parse_accounts_json( @@ -340,7 +319,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -349,7 +328,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_parse_optional_parsed_json( @@ -361,11 +340,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -377,7 +358,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -412,7 +393,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } fn kb_extract_account( @@ -422,7 +403,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTradeSide { @@ -432,7 +413,7 @@ fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTra if kb_log_messages_contain_keyword(log_messages, "sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } #[cfg(test)] @@ -462,7 +443,7 @@ mod tests { .to_string(), ); dto.id = Some(801); - dto + return dto; } fn make_create_instruction() -> crate::KbChainInstructionDto { @@ -498,7 +479,7 @@ mod tests { ), ); dto.id = Some(802); - dto + return dto; } fn make_swap_transaction() -> crate::KbChainTransactionDto { @@ -526,7 +507,7 @@ mod tests { .to_string(), ); dto.id = Some(803); - dto + return dto; } fn make_swap_instruction() -> crate::KbChainInstructionDto { @@ -559,7 +540,7 @@ mod tests { ), ); dto.id = Some(804); - dto + return dto; } #[test] @@ -584,10 +565,10 @@ mod tests { Some("So11111111111111111111111111111111111111112".to_string()) ); assert_eq!(event.fee_tier, Some("0.3%".to_string())); - } + }, crate::KbDexlabDecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } @@ -612,10 +593,10 @@ mod tests { event.token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - } + }, crate::KbDexlabDecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } } diff --git a/kb_lib/src/dex/fluxbeam.rs b/kb_lib/src/dex/fluxbeam.rs index 3c79284..34156b1 100644 --- a/kb_lib/src/dex/fluxbeam.rs +++ b/kb_lib/src/dex/fluxbeam.rs @@ -76,7 +76,7 @@ enum KbFluxbeamInstructionKind { impl KbFluxbeamDecoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more FluxBeam events. @@ -93,7 +93,7 @@ impl KbFluxbeamDecoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -104,7 +104,7 @@ impl KbFluxbeamDecoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -140,50 +140,29 @@ impl KbFluxbeamDecoder { kb_classify_instruction_kind(parsed_json.as_ref(), &log_messages); let pool_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "pool", - "poolAddress", - "poolAccount", - "amm", - "ammPool", - "poolState", - ], + &["pool", "poolAddress", "poolAccount", "amm", "ammPool", "poolState"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let lp_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["lpMint", "lp_mint", "lpTokenMint"], ) - .or_else(|| kb_extract_account(&accounts, 1)); + .or_else(|| return kb_extract_account(&accounts, 1)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenA", - "tokenAMint", - "mintA", - "baseMint", - "token0Mint", - "mint0", - ], + &["tokenA", "tokenAMint", "mintA", "baseMint", "token0Mint", "mint0"], ) - .or_else(|| kb_extract_account(&accounts, 2)); + .or_else(|| return kb_extract_account(&accounts, 2)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenB", - "tokenBMint", - "mintB", - "quoteMint", - "token1Mint", - "mint1", - ], + &["tokenB", "tokenBMint", "mintB", "quoteMint", "token1Mint", "mint1"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let creator = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["payer", "creator", "user", "owner"], ) - .or_else(|| kb_extract_account(&accounts, 4)); + .or_else(|| return kb_extract_account(&accounts, 4)); if instruction_kind == KbFluxbeamInstructionKind::CreatePool { let payload_json = serde_json::json!({ "decoder": "fluxbeam", @@ -247,7 +226,7 @@ impl KbFluxbeamDecoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -278,7 +257,7 @@ fn kb_classify_instruction_kind( if kb_log_messages_contain_keyword(log_messages, "swap") { return KbFluxbeamInstructionKind::Swap; } - KbFluxbeamInstructionKind::Unknown + return KbFluxbeamInstructionKind::Unknown; } fn kb_extract_log_messages( @@ -305,7 +284,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -316,7 +295,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_normalize_text(value: &str) -> std::string::String { @@ -326,7 +305,7 @@ fn kb_normalize_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } fn kb_parse_accounts_json( @@ -340,7 +319,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -349,7 +328,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_parse_optional_parsed_json( @@ -361,11 +340,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -377,7 +358,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -412,7 +393,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } fn kb_extract_account( @@ -422,7 +403,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTradeSide { @@ -432,7 +413,7 @@ fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTra if kb_log_messages_contain_keyword(log_messages, "sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } #[cfg(test)] @@ -462,7 +443,7 @@ mod tests { .to_string(), ); dto.id = Some(701); - dto + return dto; } fn make_create_instruction() -> crate::KbChainInstructionDto { @@ -499,7 +480,7 @@ mod tests { ), ); dto.id = Some(702); - dto + return dto; } fn make_swap_transaction() -> crate::KbChainTransactionDto { @@ -527,7 +508,7 @@ mod tests { .to_string(), ); dto.id = Some(703); - dto + return dto; } fn make_swap_instruction() -> crate::KbChainInstructionDto { @@ -561,7 +542,7 @@ mod tests { ), ); dto.id = Some(704); - dto + return dto; } #[test] @@ -586,10 +567,10 @@ mod tests { event.token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - } + }, crate::KbFluxbeamDecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } @@ -614,10 +595,10 @@ mod tests { event.token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - } + }, crate::KbFluxbeamDecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } } diff --git a/kb_lib/src/dex/meteora_damm_v1.rs b/kb_lib/src/dex/meteora_damm_v1.rs index 9dc5dd9..bffc35c 100644 --- a/kb_lib/src/dex/meteora_damm_v1.rs +++ b/kb_lib/src/dex/meteora_damm_v1.rs @@ -79,7 +79,7 @@ enum KbMeteoraDammV1InstructionKind { impl KbMeteoraDammV1Decoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more Meteora DAMM v1 events. @@ -96,7 +96,7 @@ impl KbMeteoraDammV1Decoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -107,7 +107,7 @@ impl KbMeteoraDammV1Decoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -143,50 +143,29 @@ impl KbMeteoraDammV1Decoder { kb_classify_instruction_kind(parsed_json.as_ref(), &log_messages); let pool_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "pool", - "poolAddress", - "poolAccount", - "amm", - "ammPool", - "poolState", - ], + &["pool", "poolAddress", "poolAccount", "amm", "ammPool", "poolState"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenAMint", - "mintA", - "baseMint", - "token0Mint", - "mint0", - "coinMint", - ], + &["tokenAMint", "mintA", "baseMint", "token0Mint", "mint0", "coinMint"], ) - .or_else(|| kb_extract_account(&accounts, 1)); + .or_else(|| return kb_extract_account(&accounts, 1)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenBMint", - "mintB", - "quoteMint", - "token1Mint", - "mint1", - "pcMint", - ], + &["tokenBMint", "mintB", "quoteMint", "token1Mint", "mint1", "pcMint"], ) - .or_else(|| kb_extract_account(&accounts, 2)); + .or_else(|| return kb_extract_account(&accounts, 2)); let config_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["config", "poolConfig", "ammConfig", "tradeFeeConfig"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let creator = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["creator", "payer", "user", "owner"], ) - .or_else(|| kb_extract_account(&accounts, 4)); + .or_else(|| return kb_extract_account(&accounts, 4)); if instruction_kind == KbMeteoraDammV1InstructionKind::CreatePool || instruction_kind == KbMeteoraDammV1InstructionKind::CreatePoolWithConfig { @@ -257,7 +236,7 @@ impl KbMeteoraDammV1Decoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -297,7 +276,7 @@ fn kb_classify_instruction_kind( if kb_log_messages_contain_keyword(log_messages, "swap") { return KbMeteoraDammV1InstructionKind::Swap; } - KbMeteoraDammV1InstructionKind::Unknown + return KbMeteoraDammV1InstructionKind::Unknown; } fn kb_extract_log_messages( @@ -325,7 +304,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -336,7 +315,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_normalize_text(value: &str) -> std::string::String { @@ -346,7 +325,7 @@ fn kb_normalize_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } fn kb_parse_accounts_json( @@ -360,7 +339,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -369,7 +348,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_parse_optional_parsed_json( @@ -381,11 +360,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -397,7 +378,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -432,7 +413,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } fn kb_value_contains_any_key( @@ -443,7 +424,7 @@ fn kb_value_contains_any_key( Some(value) => value, None => return false, }; - kb_value_contains_any_key_inner(value, candidate_keys) + return kb_value_contains_any_key_inner(value, candidate_keys); } fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[&str]) -> bool { @@ -467,7 +448,7 @@ fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[ } } } - false + return false; } fn kb_extract_account( @@ -477,7 +458,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTradeSide { @@ -487,7 +468,7 @@ fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTra if kb_log_messages_contain_keyword(log_messages, "sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } #[cfg(test)] @@ -517,7 +498,7 @@ mod tests { .to_string(), ); dto.id = Some(501); - dto + return dto; } fn make_create_instruction() -> crate::KbChainInstructionDto { @@ -554,7 +535,7 @@ mod tests { ), ); dto.id = Some(502); - dto + return dto; } fn make_swap_transaction() -> crate::KbChainTransactionDto { @@ -582,7 +563,7 @@ mod tests { .to_string(), ); dto.id = Some(503); - dto + return dto; } fn make_swap_instruction() -> crate::KbChainInstructionDto { @@ -615,7 +596,7 @@ mod tests { ), ); dto.id = Some(504); - dto + return dto; } #[test] @@ -640,10 +621,10 @@ mod tests { Some("So11111111111111111111111111111111111111112".to_string()) ); assert!(event.used_config); - } + }, crate::KbMeteoraDammV1DecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } @@ -668,10 +649,10 @@ mod tests { event.token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - } + }, crate::KbMeteoraDammV1DecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } } diff --git a/kb_lib/src/dex/meteora_damm_v2.rs b/kb_lib/src/dex/meteora_damm_v2.rs index f93dc2e..adfbbba 100644 --- a/kb_lib/src/dex/meteora_damm_v2.rs +++ b/kb_lib/src/dex/meteora_damm_v2.rs @@ -82,7 +82,7 @@ enum KbMeteoraDammV2InstructionKind { impl KbMeteoraDammV2Decoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more Meteora DAMM v2 events. @@ -99,7 +99,7 @@ impl KbMeteoraDammV2Decoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -110,7 +110,7 @@ impl KbMeteoraDammV2Decoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -148,27 +148,27 @@ impl KbMeteoraDammV2Decoder { parsed_json.as_ref(), &["pool", "poolAddress", "poolAccount", "poolState", "cpAmm"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["tokenAMint", "mintA", "baseMint", "token0Mint", "mint0"], ) - .or_else(|| kb_extract_account(&accounts, 1)); + .or_else(|| return kb_extract_account(&accounts, 1)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["tokenBMint", "mintB", "quoteMint", "token1Mint", "mint1"], ) - .or_else(|| kb_extract_account(&accounts, 2)); + .or_else(|| return kb_extract_account(&accounts, 2)); let config_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["staticConfig", "dynamicConfig", "config", "poolConfig"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let creator = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["creator", "payer", "user", "owner"], ) - .or_else(|| kb_extract_account(&accounts, 4)); + .or_else(|| return kb_extract_account(&accounts, 4)); if instruction_kind == KbMeteoraDammV2InstructionKind::CreatePoolStatic || instruction_kind == KbMeteoraDammV2InstructionKind::CreatePoolDynamic || instruction_kind == KbMeteoraDammV2InstructionKind::CreatePoolCustomizable @@ -178,7 +178,7 @@ impl KbMeteoraDammV2Decoder { KbMeteoraDammV2InstructionKind::CreatePoolDynamic => "dynamic".to_string(), KbMeteoraDammV2InstructionKind::CreatePoolCustomizable => { "customizable".to_string() - } + }, _ => "unknown".to_string(), }; let payload_json = serde_json::json!({ @@ -249,7 +249,7 @@ impl KbMeteoraDammV2Decoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -278,7 +278,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_classify_instruction_kind( @@ -333,7 +333,7 @@ fn kb_classify_instruction_kind( { return KbMeteoraDammV2InstructionKind::Swap; } - KbMeteoraDammV2InstructionKind::Unknown + return KbMeteoraDammV2InstructionKind::Unknown; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -344,7 +344,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_normalize_text(value: &str) -> std::string::String { @@ -354,7 +354,7 @@ fn kb_normalize_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } fn kb_parse_accounts_json( @@ -368,7 +368,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -377,7 +377,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_parse_optional_parsed_json( @@ -389,11 +389,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -405,7 +407,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -440,7 +442,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } fn kb_value_contains_any_key( @@ -451,7 +453,7 @@ fn kb_value_contains_any_key( Some(value) => value, None => return false, }; - kb_value_contains_any_key_inner(value, candidate_keys) + return kb_value_contains_any_key_inner(value, candidate_keys); } fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[&str]) -> bool { @@ -475,7 +477,7 @@ fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[ } } } - false + return false; } fn kb_extract_account( @@ -485,7 +487,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTradeSide { @@ -495,7 +497,7 @@ fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTra if kb_log_messages_contain_keyword(log_messages, "sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } #[cfg(test)] @@ -525,7 +527,7 @@ mod tests { .to_string(), ); dto.id = Some(401); - dto + return dto; } fn make_create_instruction() -> crate::KbChainInstructionDto { @@ -562,7 +564,7 @@ mod tests { ), ); dto.id = Some(402); - dto + return dto; } fn make_swap_transaction() -> crate::KbChainTransactionDto { @@ -590,7 +592,7 @@ mod tests { .to_string(), ); dto.id = Some(403); - dto + return dto; } fn make_swap_instruction() -> crate::KbChainInstructionDto { @@ -623,7 +625,7 @@ mod tests { ), ); dto.id = Some(404); - dto + return dto; } #[test] @@ -648,10 +650,10 @@ mod tests { Some("So11111111111111111111111111111111111111112".to_string()) ); assert_eq!(event.create_kind, "customizable".to_string()); - } + }, crate::KbMeteoraDammV2DecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } @@ -677,10 +679,10 @@ mod tests { Some("So11111111111111111111111111111111111111112".to_string()) ); assert!(event.used_swap2); - } + }, crate::KbMeteoraDammV2DecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } } diff --git a/kb_lib/src/dex/meteora_dbc.rs b/kb_lib/src/dex/meteora_dbc.rs index bff833a..b686abc 100644 --- a/kb_lib/src/dex/meteora_dbc.rs +++ b/kb_lib/src/dex/meteora_dbc.rs @@ -76,7 +76,7 @@ pub struct KbMeteoraDbcDecoder; impl KbMeteoraDbcDecoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more Meteora DBC events. @@ -93,7 +93,7 @@ impl KbMeteoraDbcDecoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -104,7 +104,7 @@ impl KbMeteoraDbcDecoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -142,27 +142,27 @@ impl KbMeteoraDbcDecoder { parsed_json.as_ref(), &["pool", "poolAccount", "poolState", "virtualPool", "poolKey"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["baseMint", "tokenAMint", "mintA", "token0Mint", "mint0"], ) - .or_else(|| kb_extract_account(&accounts, 1)); + .or_else(|| return kb_extract_account(&accounts, 1)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["quoteMint", "tokenBMint", "mintB", "token1Mint", "mint1"], ) - .or_else(|| kb_extract_account(&accounts, 2)); + .or_else(|| return kb_extract_account(&accounts, 2)); let config_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["poolConfig", "config", "dbcConfig", "curveConfig"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let creator = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["creator", "poolCreator", "owner", "user"], ) - .or_else(|| kb_extract_account(&accounts, 4)); + .or_else(|| return kb_extract_account(&accounts, 4)); if instruction_kind == KbMeteoraDbcInstructionKind::CreatePool { let payload_json = serde_json::json!({ "decoder": "meteora_dbc", @@ -228,7 +228,7 @@ impl KbMeteoraDbcDecoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -257,7 +257,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_log_messages_contain_any_keyword( @@ -269,7 +269,7 @@ fn kb_log_messages_contain_any_keyword( return true; } } - false + return false; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -280,7 +280,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_normalize_log_text(value: &str) -> std::string::String { @@ -290,7 +290,7 @@ fn kb_normalize_log_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } fn kb_parse_accounts_json( @@ -304,7 +304,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -313,7 +313,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_parse_optional_parsed_json( @@ -325,11 +325,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -341,7 +343,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -376,7 +378,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } fn kb_value_contains_any_key( @@ -387,7 +389,7 @@ fn kb_value_contains_any_key( Some(value) => value, None => return false, }; - kb_value_contains_any_key_inner(value, candidate_keys) + return kb_value_contains_any_key_inner(value, candidate_keys); } fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[&str]) -> bool { @@ -411,7 +413,7 @@ fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[ } } } - false + return false; } fn kb_extract_account( @@ -421,7 +423,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTradeSide { @@ -431,7 +433,7 @@ fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTra if kb_log_messages_contain_keyword(log_messages, "sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } fn kb_classify_instruction_kind( @@ -456,32 +458,21 @@ fn kb_classify_instruction_kind( } let has_create_config = kb_value_contains_any_key( parsed_json, - &[ - "poolConfig", - "migrationQuoteThreshold", - "curveConfig", - "dbcConfig", - ], + &["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", - ], + &["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 + return KbMeteoraDbcInstructionKind::Unknown; } #[cfg(test)] @@ -511,7 +502,7 @@ mod tests { .to_string(), ); dto.id = Some(301); - dto + return dto; } fn make_create_instruction() -> crate::KbChainInstructionDto { @@ -547,7 +538,7 @@ mod tests { ), ); dto.id = Some(302); - dto + return dto; } fn make_swap_transaction() -> crate::KbChainTransactionDto { @@ -575,7 +566,7 @@ mod tests { .to_string(), ); dto.id = Some(303); - dto + return dto; } fn make_swap_instruction() -> crate::KbChainInstructionDto { @@ -607,7 +598,7 @@ mod tests { ), ); dto.id = Some(304); - dto + return dto; } #[test] @@ -632,10 +623,10 @@ mod tests { Some("So11111111111111111111111111111111111111112".to_string()) ); assert_eq!(event.config_account, Some("DbcConfig111".to_string())); - } + }, crate::KbMeteoraDbcDecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } @@ -660,10 +651,10 @@ mod tests { event.token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - } + }, crate::KbMeteoraDbcDecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } @@ -687,10 +678,10 @@ mod tests { }; assert_eq!(decoded.len(), 1); match &decoded[0] { - crate::KbMeteoraDbcDecodedEvent::Swap(_) => {} + crate::KbMeteoraDbcDecodedEvent::Swap(_) => {}, crate::KbMeteoraDbcDecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } @@ -706,10 +697,10 @@ mod tests { }; assert_eq!(decoded.len(), 1); match &decoded[0] { - crate::KbMeteoraDbcDecodedEvent::CreatePool(_) => {} + crate::KbMeteoraDbcDecodedEvent::CreatePool(_) => {}, crate::KbMeteoraDbcDecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } } diff --git a/kb_lib/src/dex/orca_whirlpools.rs b/kb_lib/src/dex/orca_whirlpools.rs index 72afad6..72095fa 100644 --- a/kb_lib/src/dex/orca_whirlpools.rs +++ b/kb_lib/src/dex/orca_whirlpools.rs @@ -3,8 +3,7 @@ //! Orca Whirlpools transaction decoder. /// Orca Whirlpools program id. -pub const KB_ORCA_WHIRLPOOLS_PROGRAM_ID: &str = - "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"; +pub const KB_ORCA_WHIRLPOOLS_PROGRAM_ID: &str = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"; /// Decoded Orca Whirlpools create-pool event. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -83,7 +82,7 @@ enum KbOrcaWhirlpoolsInstructionKind { impl KbOrcaWhirlpoolsDecoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more Orca Whirlpools events. @@ -100,7 +99,7 @@ impl KbOrcaWhirlpoolsDecoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -111,7 +110,7 @@ impl KbOrcaWhirlpoolsDecoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -137,7 +136,8 @@ impl KbOrcaWhirlpoolsDecoder { Ok(accounts) => accounts, Err(error) => return Err(error), }; - let parsed_json_result = kb_parse_optional_parsed_json(instruction.parsed_json.as_ref()); + let parsed_json_result = + kb_parse_optional_parsed_json(instruction.parsed_json.as_ref()); let parsed_json = match parsed_json_result { Ok(parsed_json) => parsed_json, Err(error) => return Err(error), @@ -146,59 +146,33 @@ impl KbOrcaWhirlpoolsDecoder { kb_classify_instruction_kind(parsed_json.as_ref(), &log_messages); let pool_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "whirlpool", - "pool", - "poolAddress", - "poolAccount", - "whirlpoolAddress", - ], + &["whirlpool", "pool", "poolAddress", "poolAccount", "whirlpoolAddress"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenMintA", - "tokenAMint", - "mintA", - "baseMint", - "token0Mint", - "mint0", - ], + &["tokenMintA", "tokenAMint", "mintA", "baseMint", "token0Mint", "mint0"], ) - .or_else(|| kb_extract_account(&accounts, 1)); + .or_else(|| return kb_extract_account(&accounts, 1)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenMintB", - "tokenBMint", - "mintB", - "quoteMint", - "token1Mint", - "mint1", - ], + &["tokenMintB", "tokenBMint", "mintB", "quoteMint", "token1Mint", "mint1"], ) - .or_else(|| kb_extract_account(&accounts, 2)); + .or_else(|| return kb_extract_account(&accounts, 2)); let config_account = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "whirlpoolsConfig", - "config", - "configAccount", - "whirlpoolConfig", - ], + &["whirlpoolsConfig", "config", "configAccount", "whirlpoolConfig"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let creator = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), &["funder", "creator", "payer", "user", "owner"], ) - .or_else(|| kb_extract_account(&accounts, 4)); + .or_else(|| return kb_extract_account(&accounts, 4)); if instruction_kind == KbOrcaWhirlpoolsInstructionKind::InitializePool || instruction_kind == KbOrcaWhirlpoolsInstructionKind::InitializePoolV2 { - let used_v2 = - instruction_kind == KbOrcaWhirlpoolsInstructionKind::InitializePoolV2; + let used_v2 = instruction_kind == KbOrcaWhirlpoolsInstructionKind::InitializePoolV2; let payload_json = serde_json::json!({ "decoder": "orca_whirlpools", "eventKind": "create_pool", @@ -268,7 +242,7 @@ impl KbOrcaWhirlpoolsDecoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -295,17 +269,13 @@ fn kb_classify_instruction_kind( return KbOrcaWhirlpoolsInstructionKind::Swap; } } - if kb_value_contains_any_key( - parsed_json, - &["tokenProgramA", "tokenProgramB", "memoProgram"], - ) && kb_log_messages_contain_keyword(log_messages, "initialize_pool") + if kb_value_contains_any_key(parsed_json, &["tokenProgramA", "tokenProgramB", "memoProgram"]) + && kb_log_messages_contain_keyword(log_messages, "initialize_pool") { return KbOrcaWhirlpoolsInstructionKind::InitializePoolV2; } - if kb_value_contains_any_key( - parsed_json, - &["tokenProgramA", "tokenProgramB", "memoProgram"], - ) && kb_log_messages_contain_keyword(log_messages, "swap") + if kb_value_contains_any_key(parsed_json, &["tokenProgramA", "tokenProgramB", "memoProgram"]) + && kb_log_messages_contain_keyword(log_messages, "swap") { return KbOrcaWhirlpoolsInstructionKind::SwapV2; } @@ -327,7 +297,7 @@ fn kb_classify_instruction_kind( if kb_log_messages_contain_keyword(log_messages, "swap") { return KbOrcaWhirlpoolsInstructionKind::Swap; } - KbOrcaWhirlpoolsInstructionKind::Unknown + return KbOrcaWhirlpoolsInstructionKind::Unknown; } fn kb_extract_log_messages( @@ -355,13 +325,10 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } -fn kb_log_messages_contain_keyword( - log_messages: &[std::string::String], - keyword: &str, -) -> bool { +fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { let keyword_normalized = kb_normalize_text(keyword); for log_message in log_messages { let log_normalized = kb_normalize_text(log_message.as_str()); @@ -369,7 +336,7 @@ fn kb_log_messages_contain_keyword( return true; } } - false + return false; } fn kb_normalize_text(value: &str) -> std::string::String { @@ -379,7 +346,7 @@ fn kb_normalize_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } fn kb_parse_accounts_json( @@ -393,7 +360,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -402,7 +369,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_parse_optional_parsed_json( @@ -414,11 +381,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -430,7 +399,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -466,7 +435,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } fn kb_value_contains_any_key( @@ -477,13 +446,10 @@ fn kb_value_contains_any_key( Some(value) => value, None => return false, }; - kb_value_contains_any_key_inner(value, candidate_keys) + return kb_value_contains_any_key_inner(value, candidate_keys); } -fn kb_value_contains_any_key_inner( - value: &serde_json::Value, - candidate_keys: &[&str], -) -> bool { +fn kb_value_contains_any_key_inner(value: &serde_json::Value, candidate_keys: &[&str]) -> bool { if let Some(object) = value.as_object() { for candidate_key in candidate_keys { if object.contains_key(*candidate_key) { @@ -504,7 +470,7 @@ fn kb_value_contains_any_key_inner( } } } - false + return false; } fn kb_extract_account( @@ -514,19 +480,17 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } -fn kb_infer_trade_side( - log_messages: &[std::string::String], -) -> crate::KbSwapTradeSide { +fn kb_infer_trade_side(log_messages: &[std::string::String]) -> crate::KbSwapTradeSide { if kb_log_messages_contain_keyword(log_messages, "buy") { return crate::KbSwapTradeSide::BuyBase; } if kb_log_messages_contain_keyword(log_messages, "sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } #[cfg(test)] @@ -556,7 +520,7 @@ mod tests { .to_string(), ); dto.id = Some(601); - dto + return dto; } fn make_create_instruction() -> crate::KbChainInstructionDto { @@ -595,7 +559,7 @@ mod tests { ), ); dto.id = Some(602); - dto + return dto; } fn make_swap_transaction() -> crate::KbChainTransactionDto { @@ -623,7 +587,7 @@ mod tests { .to_string(), ); dto.id = Some(603); - dto + return dto; } fn make_swap_instruction() -> crate::KbChainInstructionDto { @@ -656,7 +620,7 @@ mod tests { ), ); dto.id = Some(604); - dto + return dto; } #[test] @@ -682,10 +646,10 @@ mod tests { ); assert_eq!(event.config_account, Some("OrcaConfig111".to_string())); assert!(event.used_v2); - } + }, crate::KbOrcaWhirlpoolsDecodedEvent::Swap(_) => { panic!("unexpected swap event") - } + }, } } @@ -711,10 +675,10 @@ mod tests { Some("So11111111111111111111111111111111111111112".to_string()) ); assert!(event.used_v2); - } + }, crate::KbOrcaWhirlpoolsDecodedEvent::CreatePool(_) => { panic!("unexpected create event") - } + }, } } } diff --git a/kb_lib/src/dex/pump_fun.rs b/kb_lib/src/dex/pump_fun.rs index 7b203b4..d094c7c 100644 --- a/kb_lib/src/dex/pump_fun.rs +++ b/kb_lib/src/dex/pump_fun.rs @@ -80,7 +80,7 @@ pub struct KbPumpFunDecoder; impl KbPumpFunDecoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more Pump.fun events. @@ -97,7 +97,7 @@ impl KbPumpFunDecoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; if transaction.err_json.is_some() { return Ok(std::vec::Vec::new()); @@ -111,7 +111,7 @@ impl KbPumpFunDecoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let has_create_v2_log = kb_log_messages_contain_keyword(&log_messages, "create_v2") @@ -250,7 +250,7 @@ impl KbPumpFunDecoder { }, )); } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -271,8 +271,8 @@ fn kb_decode_optional_instruction_data( }; let decode_result = bs58::decode(encoded.as_str()).into_vec(); match decode_result { - Ok(decoded) => Some(decoded), - Err(_) => None, + Ok(decoded) => return Some(decoded), + Err(_) => return None, } } @@ -287,7 +287,7 @@ fn kb_instruction_data_starts_with( if instruction_data.len() < discriminator.len() { return false; } - &instruction_data[0..discriminator.len()] == discriminator + return &instruction_data[0..discriminator.len()] == discriminator; } fn kb_extract_u64_argument( @@ -304,7 +304,7 @@ fn kb_extract_u64_argument( } let mut bytes = [0u8; 8]; bytes.copy_from_slice(&instruction_data[offset..end]); - Some(u64::from_le_bytes(bytes).to_string()) + return Some(u64::from_le_bytes(bytes).to_string()); } fn kb_extract_log_messages( @@ -332,7 +332,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -343,7 +343,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_parse_accounts_json( @@ -357,7 +357,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -366,7 +366,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_extract_account( @@ -376,7 +376,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_normalize_log_text(value: &str) -> std::string::String { @@ -386,7 +386,7 @@ fn kb_normalize_log_text(value: &str) -> std::string::String { normalized.push(character.to_ascii_lowercase()); } } - normalized + return normalized; } #[cfg(test)] @@ -416,7 +416,7 @@ mod tests { .to_string(), ); dto.id = Some(91); - dto + return dto; } fn make_instruction() -> crate::KbChainInstructionDto { @@ -445,7 +445,7 @@ mod tests { None, ); dto.id = Some(17); - dto + return dto; } #[test] @@ -470,13 +470,13 @@ mod tests { Some("AssociatedBondingCurve111".to_string()) ); assert_eq!(event.creator, Some("Creator111".to_string())); - } + }, crate::KbPumpFunDecodedEvent::BuyTrade(_) => { panic!("unexpected pump_fun buy trade event"); - } + }, crate::KbPumpFunDecodedEvent::SellTrade(_) => { panic!("unexpected pump_fun sell trade event"); - } + }, } } diff --git a/kb_lib/src/dex/pump_swap.rs b/kb_lib/src/dex/pump_swap.rs index 9c9ed2b..29d50ff 100644 --- a/kb_lib/src/dex/pump_swap.rs +++ b/kb_lib/src/dex/pump_swap.rs @@ -46,7 +46,7 @@ pub struct KbPumpSwapDecoder; impl KbPumpSwapDecoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more PumpSwap events. @@ -63,7 +63,7 @@ impl KbPumpSwapDecoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -74,7 +74,7 @@ impl KbPumpSwapDecoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let mut decoded_events = std::vec::Vec::new(); @@ -110,40 +110,20 @@ impl KbPumpSwapDecoder { parsed_json.as_ref(), &["pool", "poolAccount", "amm", "ammPool", "poolState"], ) - .or_else(|| kb_extract_account(&accounts, 0)); + .or_else(|| return kb_extract_account(&accounts, 0)); let token_a_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenAMint", - "baseMint", - "mintA", - "coinMint", - "token0Mint", - "mint0", - ], + &["tokenAMint", "baseMint", "mintA", "coinMint", "token0Mint", "mint0"], ) - .or_else(|| kb_extract_account(&accounts, 3)); + .or_else(|| return kb_extract_account(&accounts, 3)); let token_b_mint = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "tokenBMint", - "quoteMint", - "mintB", - "pcMint", - "token1Mint", - "mint1", - ], + &["tokenBMint", "quoteMint", "mintB", "pcMint", "token1Mint", "mint1"], ) - .or_else(|| kb_extract_account(&accounts, 4)); + .or_else(|| return kb_extract_account(&accounts, 4)); let pool_v2 = kb_extract_string_by_candidate_keys( parsed_json.as_ref(), - &[ - "poolV2", - "pool_v2", - "ammV2", - "bondingCurveV2", - "bonding_curve_v2", - ], + &["poolV2", "pool_v2", "ammV2", "bondingCurveV2", "bonding_curve_v2"], ); let pool_base_token_account = kb_extract_account(&accounts, 7); let pool_quote_token_account = kb_extract_account(&accounts, 8); @@ -200,7 +180,7 @@ impl KbPumpSwapDecoder { )); } } - Ok(decoded_events) + return Ok(decoded_events); } } @@ -230,7 +210,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages; } fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword: &str) -> bool { @@ -241,7 +221,7 @@ fn kb_log_messages_contain_keyword(log_messages: &[std::string::String], keyword return true; } } - false + return false; } fn kb_parse_accounts_json( @@ -255,7 +235,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -264,7 +244,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts); } fn kb_extract_account( @@ -274,7 +254,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()); } fn kb_parse_optional_parsed_json( @@ -286,11 +266,13 @@ fn kb_parse_optional_parsed_json( }; let value_result = serde_json::from_str::(parsed_json.as_str()); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse instruction parsed_json '{}': {}", - parsed_json, error - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse instruction parsed_json '{}': {}", + parsed_json, error + ))); + }, } } @@ -302,7 +284,7 @@ fn kb_extract_string_by_candidate_keys( Some(value) => value, None => return None, }; - kb_extract_string_by_candidate_keys_inner(value, candidate_keys) + return kb_extract_string_by_candidate_keys_inner(value, candidate_keys); } fn kb_extract_string_by_candidate_keys_inner( @@ -337,7 +319,7 @@ fn kb_extract_string_by_candidate_keys_inner( } } } - None + return None; } #[cfg(test)] @@ -367,7 +349,7 @@ mod tests { .to_string(), ); dto.id = Some(92); - dto + return dto; } fn make_instruction() -> crate::KbChainInstructionDto { @@ -389,7 +371,8 @@ mod tests { "UserQuoteAta111", "PoolBaseVault111", "PoolQuoteVault111" - ]).to_string(), + ]) + .to_string(), None, None, Some( @@ -405,7 +388,7 @@ mod tests { ), ); dto.id = Some(18); - dto + return dto; } #[test] @@ -436,10 +419,10 @@ mod tests { Some(&serde_json::Value::String("PoolQuoteVault111".to_string())) ); assert_eq!(event.trade_side, crate::KbSwapTradeSide::BuyBase); - } + }, crate::KbPumpSwapDecodedEvent::SellTrade(_) => { panic!("unexpected sell event") - } + }, } } diff --git a/kb_lib/src/dex/raydium_amm_v4.rs b/kb_lib/src/dex/raydium_amm_v4.rs index 5429e97..0d7c0c8 100644 --- a/kb_lib/src/dex/raydium_amm_v4.rs +++ b/kb_lib/src/dex/raydium_amm_v4.rs @@ -44,7 +44,7 @@ pub struct KbRaydiumAmmV4Decoder; impl KbRaydiumAmmV4Decoder { /// Creates a new decoder. pub fn new() -> Self { - Self + return Self; } /// Decodes one projected transaction into zero or more Raydium AmmV4 events. @@ -61,7 +61,7 @@ impl KbRaydiumAmmV4Decoder { "chain transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let transaction_json_result = serde_json::from_str::(transaction.transaction_json.as_str()); @@ -72,7 +72,7 @@ impl KbRaydiumAmmV4Decoder { "cannot parse transaction_json for signature '{}': {}", transaction.signature, error ))); - } + }, }; let log_messages = kb_extract_log_messages(&transaction_json); let has_initialize2_log = kb_log_messages_contain_initialize2(&log_messages); @@ -139,7 +139,7 @@ impl KbRaydiumAmmV4Decoder { }, )); } - Ok(decoded_events) + return Ok(decoded_events) } } @@ -168,7 +168,7 @@ fn kb_extract_log_messages( messages.push(text.to_string()); } } - messages + return messages } fn kb_log_messages_contain_initialize2(log_messages: &[std::string::String]) -> bool { @@ -177,7 +177,7 @@ fn kb_log_messages_contain_initialize2(log_messages: &[std::string::String]) -> return true; } } - false + return false } fn kb_parse_accounts_json( @@ -191,7 +191,7 @@ fn kb_parse_accounts_json( "cannot parse instruction accounts_json '{}': {}", accounts_json, error ))); - } + }, }; let mut accounts = std::vec::Vec::new(); for value in values { @@ -200,7 +200,7 @@ fn kb_parse_accounts_json( accounts.push(text.to_string()); } } - Ok(accounts) + return Ok(accounts) } fn kb_extract_account( @@ -210,7 +210,7 @@ fn kb_extract_account( if index >= accounts.len() { return None; } - Some(accounts[index].clone()) + return Some(accounts[index].clone()) } #[cfg(test)] @@ -240,7 +240,7 @@ mod tests { .to_string(), ); dto.id = Some(42); - dto + return dto } fn make_instruction() -> crate::KbChainInstructionDto { @@ -277,7 +277,7 @@ mod tests { None, ); dto.id = Some(7); - dto + return dto } #[test] @@ -300,7 +300,7 @@ mod tests { assert_eq!(event.token_a_mint, Some("TokenA111".to_string())); assert_eq!(event.token_b_mint, Some("TokenB111".to_string())); assert_eq!(event.market_account, Some("Market111".to_string())); - } + }, } } diff --git a/kb_lib/src/dex/raydium_clmm.rs b/kb_lib/src/dex/raydium_clmm.rs index 24e9157..972d4b9 100644 --- a/kb_lib/src/dex/raydium_clmm.rs +++ b/kb_lib/src/dex/raydium_clmm.rs @@ -20,28 +20,28 @@ impl KbRaydiumClmmDecodedEvent { /// Returns the normalized event kind. pub fn event_kind(&self) -> &'static str { match self { - crate::KbRaydiumClmmDecodedEvent::SwapV2(_) => "raydium_clmm.swap_v2", + crate::KbRaydiumClmmDecodedEvent::SwapV2(_) => return "raydium_clmm.swap_v2", } } /// Returns the pool account. pub fn pool_account(&self) -> &str { match self { - crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => event.pool_state.as_str(), + crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => return event.pool_state.as_str(), } } /// Returns the normalized base mint. pub fn base_mint(&self) -> &str { match self { - crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => event.base_mint.as_str(), + crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => return event.base_mint.as_str(), } } /// Returns the normalized quote mint. pub fn quote_mint(&self) -> &str { match self { - crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => event.quote_mint.as_str(), + crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => return event.quote_mint.as_str(), } } @@ -51,10 +51,10 @@ impl KbRaydiumClmmDecodedEvent { crate::KbRaydiumClmmDecodedEvent::SwapV2(event) => { let result = serde_json::to_string(event); match result { - Ok(payload_json) => Some(payload_json), - Err(_) => None, + Ok(payload_json) => return Some(payload_json), + Err(_) => return None, } - } + }, } } } @@ -144,7 +144,7 @@ pub fn kb_decode_raydium_clmm_instruction( None => return decoded, }; decoded.push(crate::KbRaydiumClmmDecodedEvent::SwapV2(event)); - decoded + return decoded; } fn kb_decode_swap_v2( @@ -219,7 +219,7 @@ fn kb_decode_swap_v2( quote_vault = input_vault.clone(); trade_side = "BuyBase".to_string(); } - Some(crate::KbRaydiumClmmSwapV2Decoded { + return Some(crate::KbRaydiumClmmSwapV2Decoded { payer, amm_config, pool_state, @@ -239,7 +239,7 @@ fn kb_decode_swap_v2( other_amount_threshold, sqrt_price_limit_x64: sqrt_price_limit_x64.to_string(), is_base_input, - }) + }); } fn kb_clone_account( @@ -248,8 +248,8 @@ fn kb_clone_account( ) -> std::option::Option { let account_option = accounts.get(index); match account_option { - Some(account) => Some(account.clone()), - None => None, + Some(account) => return Some(account.clone()), + None => return None, } } @@ -263,7 +263,7 @@ fn kb_read_discriminator(data: &[u8]) -> std::option::Option<[u8; 8]> { bytes[index] = data[index]; index += 1; } - Some(bytes) + return Some(bytes); } fn kb_read_u64_le(data: &[u8], offset: usize) -> std::option::Option { @@ -276,7 +276,7 @@ fn kb_read_u64_le(data: &[u8], offset: usize) -> std::option::Option { bytes[index] = data[offset + index]; index += 1; } - Some(u64::from_le_bytes(bytes)) + return Some(u64::from_le_bytes(bytes)); } fn kb_read_u128_le(data: &[u8], offset: usize) -> std::option::Option { @@ -289,7 +289,7 @@ fn kb_read_u128_le(data: &[u8], offset: usize) -> std::option::Option { bytes[index] = data[offset + index]; index += 1; } - Some(u128::from_le_bytes(bytes)) + return Some(u128::from_le_bytes(bytes)); } fn kb_read_bool(data: &[u8], offset: usize) -> std::option::Option { @@ -297,9 +297,9 @@ fn kb_read_bool(data: &[u8], offset: usize) -> std::option::Option { return None; } match data[offset] { - 0 => Some(false), - 1 => Some(true), - _ => None, + 0 => return Some(false), + 1 => return Some(true), + _ => return None, } } @@ -349,13 +349,13 @@ fn kb_decode_base58(input: &str) -> std::option::Option> { for byte in bytes { result.push(byte); } - Some(result) + return Some(result); } #[cfg(test)] mod tests { fn sample_swap_v2_accounts_json() -> &'static str { - r#"[ + return r#"[ "8NQ32SyFKD1d5kenq4oM8Da6C6J9TQSMW1uAgFRveEQr", "A1BBtTYJd4i3xU8D6Tc2FzU6ZN4oXZWXKZnCxwbHXr8x", "GUrRxvnWVQSnbcz1eP9D5BqXwPZtRhmrqVfm5wY9meWR", @@ -371,7 +371,7 @@ mod tests { "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", "8ovxZR2Gv9Mr73aoXLQYTMaZvHCSpnEohzgjVHQwmyHr", "9MssDxndh2Rn8DmGWL94hXVv22zxfDYHV7tvzfPgcaWe" - ]"# + ]"#; } #[test] @@ -388,48 +388,21 @@ mod tests { events[0].pool_account(), "GUrRxvnWVQSnbcz1eP9D5BqXwPZtRhmrqVfm5wY9meWR" ); - assert_eq!( - event.pool_state, - "GUrRxvnWVQSnbcz1eP9D5BqXwPZtRhmrqVfm5wY9meWR" - ); - assert_eq!( - event.input_vault, - "AvRzvwpSVnxsinLGQS3vZLqkZxhXZDM8F2qKccAo7rSq" - ); - assert_eq!( - event.output_vault, - "CTkc4xDrpzjWcFLC1cxmUZZjZLSRV46HZa8wu5eKTbuh" - ); - assert_eq!( - event.input_vault_mint, - "CKvjP8FrZpaKXjASEtX2nEU9w7M4RKskfnLQbKJBodV" - ); - assert_eq!( - event.output_vault_mint, - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" - ); - assert_eq!( - event.base_mint, - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" - ); - assert_eq!( - event.quote_mint, - "CKvjP8FrZpaKXjASEtX2nEU9w7M4RKskfnLQbKJBodV" - ); - assert_eq!( - event.base_vault, - "CTkc4xDrpzjWcFLC1cxmUZZjZLSRV46HZa8wu5eKTbuh" - ); - assert_eq!( - event.quote_vault, - "AvRzvwpSVnxsinLGQS3vZLqkZxhXZDM8F2qKccAo7rSq" - ); + assert_eq!(event.pool_state, "GUrRxvnWVQSnbcz1eP9D5BqXwPZtRhmrqVfm5wY9meWR"); + assert_eq!(event.input_vault, "AvRzvwpSVnxsinLGQS3vZLqkZxhXZDM8F2qKccAo7rSq"); + assert_eq!(event.output_vault, "CTkc4xDrpzjWcFLC1cxmUZZjZLSRV46HZa8wu5eKTbuh"); + assert_eq!(event.input_vault_mint, "CKvjP8FrZpaKXjASEtX2nEU9w7M4RKskfnLQbKJBodV"); + assert_eq!(event.output_vault_mint, "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"); + assert_eq!(event.base_mint, "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"); + assert_eq!(event.quote_mint, "CKvjP8FrZpaKXjASEtX2nEU9w7M4RKskfnLQbKJBodV"); + assert_eq!(event.base_vault, "CTkc4xDrpzjWcFLC1cxmUZZjZLSRV46HZa8wu5eKTbuh"); + assert_eq!(event.quote_vault, "AvRzvwpSVnxsinLGQS3vZLqkZxhXZDM8F2qKccAo7rSq"); assert_eq!(event.trade_side, "BuyBase"); assert_eq!(event.amount, 148441657491969); assert_eq!(event.other_amount_threshold, 0); assert_eq!(event.sqrt_price_limit_x64, "0"); - assert_eq!(event.is_base_input, true); - } + assert!(event.is_base_input); + }, } } @@ -476,15 +449,7 @@ mod tests { #[test] fn ignores_legacy_swap_for_now() { - let mut data = std::vec::Vec::::new(); - data.push(248); - data.push(198); - data.push(158); - data.push(145); - data.push(225); - data.push(117); - data.push(135); - data.push(200); + let mut data: std::vec::Vec = vec![248, 198, 158, 145, 225, 117, 135, 200]; while data.len() < 41 { data.push(0); } diff --git a/kb_lib/src/dex/raydium_cpmm.rs b/kb_lib/src/dex/raydium_cpmm.rs index cbe09e5..b0328df 100644 --- a/kb_lib/src/dex/raydium_cpmm.rs +++ b/kb_lib/src/dex/raydium_cpmm.rs @@ -91,32 +91,32 @@ impl KbRaydiumCpmmDecodedEvent { /// Returns the storage event kind. pub fn event_kind(&self) -> &'static str { match self { - KbRaydiumCpmmDecodedEvent::SwapBaseInput(_) => "raydium_cpmm.swap_base_input", - KbRaydiumCpmmDecodedEvent::SwapBaseOutput(_) => "raydium_cpmm.swap_base_output", + KbRaydiumCpmmDecodedEvent::SwapBaseInput(_) => return "raydium_cpmm.swap_base_input", + KbRaydiumCpmmDecodedEvent::SwapBaseOutput(_) => return "raydium_cpmm.swap_base_output", } } /// Returns the pool account. pub fn pool_account(&self) -> &str { match self { - KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => event.pool_state.as_str(), - KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => event.pool_state.as_str(), + KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => return event.pool_state.as_str(), + KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => return event.pool_state.as_str(), } } /// Returns the normalized base mint. pub fn base_mint(&self) -> &str { match self { - KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => event.base_mint.as_str(), - KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => event.base_mint.as_str(), + KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => return event.base_mint.as_str(), + KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => return event.base_mint.as_str(), } } /// Returns the normalized quote mint. pub fn quote_mint(&self) -> &str { match self { - KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => event.quote_mint.as_str(), - KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => event.quote_mint.as_str(), + KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => return event.quote_mint.as_str(), + KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => return event.quote_mint.as_str(), } } @@ -126,17 +126,17 @@ impl KbRaydiumCpmmDecodedEvent { crate::KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => { let result = serde_json::to_string(event); match result { - Ok(payload) => Some(payload), - Err(_) => None, + Ok(payload) => return Some(payload), + Err(_) => return None, } - } + }, crate::KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => { let result = serde_json::to_string(event); match result { - Ok(payload) => Some(payload), - Err(_) => None, + Ok(payload) => return Some(payload), + Err(_) => return None, } - } + }, } } } @@ -161,9 +161,7 @@ pub fn kb_decode_raydium_cpmm_instruction( if data.len() < 24 { return std::vec::Vec::new(); } - let discriminator = [ - data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], - ]; + let discriminator = [data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]]; if discriminator == KB_RAYDIUM_CPMM_SWAP_BASE_INPUT_DISCRIMINATOR { let amount_in = match kb_read_u64_le(data.as_slice(), 8) { Some(value) => value, @@ -208,7 +206,7 @@ pub fn kb_decode_raydium_cpmm_instruction( }; return vec![KbRaydiumCpmmDecodedEvent::SwapBaseOutput(swap)]; } - std::vec::Vec::new() + return std::vec::Vec::new(); } fn kb_build_raydium_cpmm_swap( @@ -233,12 +231,8 @@ fn kb_build_raydium_cpmm_swap( output_vault.as_str(), ); let input_is_base = normalized.input_is_base; - let trade_side = if input_is_base { - "sell".to_string() - } else { - "buy".to_string() - }; - Some(KbRaydiumCpmmSwapDecoded { + let trade_side = if input_is_base { "sell".to_string() } else { "buy".to_string() }; + return Some(KbRaydiumCpmmSwapDecoded { swap_mode, payer: accounts[0].clone(), authority: accounts[1].clone(), @@ -263,7 +257,7 @@ fn kb_build_raydium_cpmm_swap( minimum_amount_out_raw, max_amount_in_raw, amount_out_raw, - }) + }); } struct KbRaydiumCpmmNormalizedPair { @@ -307,13 +301,13 @@ fn kb_normalize_raydium_cpmm_pair( input_is_base: true, }; } - KbRaydiumCpmmNormalizedPair { + return KbRaydiumCpmmNormalizedPair { base_mint: output_mint.to_string(), quote_mint: input_mint.to_string(), base_vault: output_vault.to_string(), quote_vault: input_vault.to_string(), input_is_base: false, - } + }; } fn kb_is_quote_mint(mint: &str) -> bool { @@ -329,7 +323,7 @@ fn kb_is_quote_mint(mint: &str) -> bool { if mint == "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB" { return true; } - false + return false; } fn kb_parse_accounts_json( @@ -337,16 +331,15 @@ fn kb_parse_accounts_json( ) -> std::option::Option> { let result = serde_json::from_str::>(accounts_json); match result { - Ok(accounts) => Some(accounts), - Err(_) => None, + Ok(accounts) => return Some(accounts), + Err(_) => return None, } } fn kb_parse_data_json_as_base58(data_json: &str) -> std::option::Option { let json_string_result = serde_json::from_str::(data_json); - match json_string_result { - Ok(value) => return Some(value), - Err(_) => {} + if let Ok(value) = json_string_result { + return Some(value); } let trimmed = data_json.trim(); if trimmed.is_empty() { @@ -356,7 +349,7 @@ fn kb_parse_data_json_as_base58(data_json: &str) -> std::option::Option std::option::Option { @@ -373,7 +366,7 @@ fn kb_read_u64_le(data: &[u8], offset: usize) -> std::option::Option { data[offset + 6], data[offset + 7], ]; - Some(u64::from_le_bytes(bytes)) + return Some(u64::from_le_bytes(bytes)); } #[cfg(test)] @@ -402,26 +395,17 @@ mod tests { assert_eq!(events.len(), 1); match &events[0] { crate::KbRaydiumCpmmDecodedEvent::SwapBaseInput(event) => { - assert_eq!( - event.pool_state, - "2ErXvV1tKtG3wiHqdofDjMou7Jusdsfasvfh8HrTj5oV" - ); - assert_eq!( - event.base_mint, - "Pf9aSicGu3g6tTUBqrRbjNsGape9HopibspX5KSbonk" - ); - assert_eq!( - event.quote_mint, - "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB" - ); - assert_eq!(event.input_is_base, true); + assert_eq!(event.pool_state, "2ErXvV1tKtG3wiHqdofDjMou7Jusdsfasvfh8HrTj5oV"); + assert_eq!(event.base_mint, "Pf9aSicGu3g6tTUBqrRbjNsGape9HopibspX5KSbonk"); + assert_eq!(event.quote_mint, "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB"); + assert!(event.input_is_base); assert_eq!(event.trade_side, "sell"); - assert_eq!(event.amount_in_raw.is_some(), true); - assert_eq!(event.minimum_amount_out_raw.is_some(), true); - } + assert!(event.amount_in_raw.is_some()); + assert!(event.minimum_amount_out_raw.is_some()); + }, _ => { panic!("expected swap base input"); - } + }, } } #[test] @@ -448,26 +432,17 @@ mod tests { assert_eq!(events.len(), 1); match &events[0] { crate::KbRaydiumCpmmDecodedEvent::SwapBaseOutput(event) => { - assert_eq!( - event.pool_state, - "2ErXvV1tKtG3wiHqdofDjMou7Jusdsfasvfh8HrTj5oV" - ); - assert_eq!( - event.base_mint, - "Pf9aSicGu3g6tTUBqrRbjNsGape9HopibspX5KSbonk" - ); - assert_eq!( - event.quote_mint, - "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB" - ); - assert_eq!(event.input_is_base, false); + assert_eq!(event.pool_state, "2ErXvV1tKtG3wiHqdofDjMou7Jusdsfasvfh8HrTj5oV"); + assert_eq!(event.base_mint, "Pf9aSicGu3g6tTUBqrRbjNsGape9HopibspX5KSbonk"); + assert_eq!(event.quote_mint, "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB"); + assert!(!event.input_is_base); assert_eq!(event.trade_side, "buy"); - assert_eq!(event.max_amount_in_raw.is_some(), true); - assert_eq!(event.amount_out_raw.is_some(), true); - } + assert!(event.max_amount_in_raw.is_some()); + assert!(event.amount_out_raw.is_some()); + }, _ => { panic!("expected swap base output"); - } + }, } } } diff --git a/kb_lib/src/dex_decode.rs b/kb_lib/src/dex_decode.rs index f2db75d..2fcfe3b 100644 --- a/kb_lib/src/dex_decode.rs +++ b/kb_lib/src/dex_decode.rs @@ -22,7 +22,7 @@ impl KbDexDecodeService { /// Creates a new DEX decode service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { + return Self { database, persistence, raydium_amm_v4_decoder: crate::KbRaydiumAmmV4Decoder::new(), @@ -34,7 +34,7 @@ impl KbDexDecodeService { meteora_damm_v2_decoder: crate::KbMeteoraDammV2Decoder::new(), fluxbeam_decoder: crate::KbFluxbeamDecoder::new(), dexlab_decoder: crate::KbDexlabDecoder::new(), - } + }; } async fn decode_and_persist_raydium_clmm_events( @@ -60,9 +60,8 @@ impl KbDexDecodeService { data_json.as_str(), ); for decoded_event in &decoded_events { - let persist_result = self - .persist_raydium_clmm_event(transaction, instruction, decoded_event) - .await; + let persist_result = + self.persist_raydium_clmm_event(transaction, instruction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), @@ -70,7 +69,7 @@ impl KbDexDecodeService { persisted.push(persisted_event); } } - Ok(persisted) + return Ok(persisted); } /// Decodes one projected transaction and persists the decoded events. @@ -91,7 +90,7 @@ impl KbDexDecodeService { "cannot decode unknown chain transaction '{}'", signature ))); - } + }, }; let transaction_id_option = transaction.id; let transaction_id = match transaction_id_option { @@ -101,7 +100,7 @@ impl KbDexDecodeService { "chain transaction '{}' has no internal id", signature ))); - } + }, }; let instructions_result = crate::list_chain_instructions_by_transaction_id( self.database.as_ref(), @@ -113,26 +112,23 @@ impl KbDexDecodeService { Err(error) => return Err(error), }; let mut persisted = std::vec::Vec::new(); - let raydium_decoded_result = self - .raydium_amm_v4_decoder - .decode_transaction(&transaction, &instructions); + let raydium_decoded_result = + self.raydium_amm_v4_decoder.decode_transaction(&transaction, &instructions); let raydium_decoded = match raydium_decoded_result { Ok(raydium_decoded) => raydium_decoded, Err(error) => return Err(error), }; for decoded_event in &raydium_decoded { - let persist_result = self - .persist_raydium_amm_v4_event(&transaction, decoded_event) - .await; + let persist_result = + self.persist_raydium_amm_v4_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let raydium_cpmm_persisted_result = self - .decode_and_persist_raydium_cpmm_events(&transaction, &instructions) - .await; + let raydium_cpmm_persisted_result = + self.decode_and_persist_raydium_cpmm_events(&transaction, &instructions).await; let raydium_cpmm_persisted = match raydium_cpmm_persisted_result { Ok(raydium_cpmm_persisted) => raydium_cpmm_persisted, Err(error) => return Err(error), @@ -140,9 +136,8 @@ impl KbDexDecodeService { for persisted_event in raydium_cpmm_persisted { persisted.push(persisted_event); } - let raydium_clmm_persisted_result = self - .decode_and_persist_raydium_clmm_events(&transaction, &instructions) - .await; + let raydium_clmm_persisted_result = + self.decode_and_persist_raydium_clmm_events(&transaction, &instructions).await; let raydium_clmm_persisted = match raydium_clmm_persisted_result { Ok(raydium_clmm_persisted) => raydium_clmm_persisted, Err(error) => return Err(error), @@ -150,128 +145,109 @@ impl KbDexDecodeService { for persisted_event in raydium_clmm_persisted { persisted.push(persisted_event); } - let pump_fun_decoded_result = self - .pump_fun_decoder - .decode_transaction(&transaction, &instructions); + let pump_fun_decoded_result = + self.pump_fun_decoder.decode_transaction(&transaction, &instructions); let pump_fun_decoded = match pump_fun_decoded_result { Ok(pump_fun_decoded) => pump_fun_decoded, Err(error) => return Err(error), }; for decoded_event in &pump_fun_decoded { - let persist_result = self - .persist_pump_fun_event(&transaction, decoded_event) - .await; + let persist_result = self.persist_pump_fun_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let pump_swap_decoded_result = self - .pump_swap_decoder - .decode_transaction(&transaction, &instructions); + let pump_swap_decoded_result = + self.pump_swap_decoder.decode_transaction(&transaction, &instructions); let pump_swap_decoded = match pump_swap_decoded_result { Ok(pump_swap_decoded) => pump_swap_decoded, Err(error) => return Err(error), }; for decoded_event in &pump_swap_decoded { - let persist_result = self - .persist_pump_swap_event(&transaction, decoded_event) - .await; + let persist_result = self.persist_pump_swap_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let meteora_dbc_decoded_result = self - .meteora_dbc_decoder - .decode_transaction(&transaction, &instructions); + let meteora_dbc_decoded_result = + self.meteora_dbc_decoder.decode_transaction(&transaction, &instructions); let meteora_dbc_decoded = match meteora_dbc_decoded_result { Ok(meteora_dbc_decoded) => meteora_dbc_decoded, Err(error) => return Err(error), }; for decoded_event in &meteora_dbc_decoded { - let persist_result = self - .persist_meteora_dbc_event(&transaction, decoded_event) - .await; + let persist_result = self.persist_meteora_dbc_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let meteora_damm_v2_decoded_result = self - .meteora_damm_v2_decoder - .decode_transaction(&transaction, &instructions); + let meteora_damm_v2_decoded_result = + self.meteora_damm_v2_decoder.decode_transaction(&transaction, &instructions); let meteora_damm_v2_decoded = match meteora_damm_v2_decoded_result { Ok(meteora_damm_v2_decoded) => meteora_damm_v2_decoded, Err(error) => return Err(error), }; for decoded_event in &meteora_damm_v2_decoded { - let persist_result = self - .persist_meteora_damm_v2_event(&transaction, decoded_event) - .await; + let persist_result = + self.persist_meteora_damm_v2_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let meteora_damm_v1_decoded_result = self - .meteora_damm_v1_decoder - .decode_transaction(&transaction, &instructions); + let meteora_damm_v1_decoded_result = + self.meteora_damm_v1_decoder.decode_transaction(&transaction, &instructions); let meteora_damm_v1_decoded = match meteora_damm_v1_decoded_result { Ok(meteora_damm_v1_decoded) => meteora_damm_v1_decoded, Err(error) => return Err(error), }; for decoded_event in &meteora_damm_v1_decoded { - let persist_result = self - .persist_meteora_damm_v1_event(&transaction, decoded_event) - .await; + let persist_result = + self.persist_meteora_damm_v1_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let orca_whirlpools_decoded_result = self - .orca_whirlpools_decoder - .decode_transaction(&transaction, &instructions); + let orca_whirlpools_decoded_result = + self.orca_whirlpools_decoder.decode_transaction(&transaction, &instructions); let orca_whirlpools_decoded = match orca_whirlpools_decoded_result { Ok(orca_whirlpools_decoded) => orca_whirlpools_decoded, Err(error) => return Err(error), }; for decoded_event in &orca_whirlpools_decoded { - let persist_result = self - .persist_orca_whirlpools_event(&transaction, decoded_event) - .await; + let persist_result = + self.persist_orca_whirlpools_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let fluxbeam_decoded_result = self - .fluxbeam_decoder - .decode_transaction(&transaction, &instructions); + let fluxbeam_decoded_result = + self.fluxbeam_decoder.decode_transaction(&transaction, &instructions); let fluxbeam_decoded = match fluxbeam_decoded_result { Ok(fluxbeam_decoded) => fluxbeam_decoded, Err(error) => return Err(error), }; for decoded_event in &fluxbeam_decoded { - let persist_result = self - .persist_fluxbeam_event(&transaction, decoded_event) - .await; + let persist_result = self.persist_fluxbeam_event(&transaction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), }; persisted.push(persisted_event); } - let dexlab_decoded_result = self - .dexlab_decoder - .decode_transaction(&transaction, &instructions); + let dexlab_decoded_result = + self.dexlab_decoder.decode_transaction(&transaction, &instructions); let dexlab_decoded = match dexlab_decoded_result { Ok(dexlab_decoded) => dexlab_decoded, Err(error) => return Err(error), @@ -284,7 +260,7 @@ impl KbDexDecodeService { }; persisted.push(persisted_event); } - Ok(persisted) + return Ok(persisted); } async fn persist_dexlab_event( @@ -350,7 +326,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -384,8 +360,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbDexlabDecodedEvent::Swap(event) => { let payload_json_result = kb_enrich_and_serialize_dex_decoded_payload( "dexlab", @@ -443,7 +419,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -477,8 +453,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -545,7 +521,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -579,8 +555,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbFluxbeamDecodedEvent::Swap(event) => { let payload_json_result = kb_enrich_and_serialize_dex_decoded_payload( "fluxbeam", @@ -638,7 +614,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -672,8 +648,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -740,7 +716,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -774,8 +750,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbOrcaWhirlpoolsDecodedEvent::Swap(event) => { let payload_json_result = kb_enrich_and_serialize_dex_decoded_payload( "orca_whirlpools", @@ -833,7 +809,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -867,9 +843,8 @@ impl KbDexDecodeService { return Err(error); } } - - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -936,7 +911,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -970,8 +945,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbMeteoraDammV1DecodedEvent::Swap(event) => { let payload_json_result = kb_enrich_and_serialize_dex_decoded_payload( "meteora_damm_v1", @@ -1029,7 +1004,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1063,8 +1038,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -1131,7 +1106,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1165,8 +1140,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbMeteoraDammV2DecodedEvent::Swap(event) => { let payload_json_result = kb_enrich_and_serialize_dex_decoded_payload( "meteora_damm_v2", @@ -1224,7 +1199,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1258,8 +1233,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -1326,7 +1301,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1360,8 +1335,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbMeteoraDbcDecodedEvent::Swap(event) => { let payload_json_result = kb_enrich_and_serialize_dex_decoded_payload( "meteora_dbc", @@ -1419,7 +1394,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1453,8 +1428,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -1521,7 +1496,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1555,8 +1530,8 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, } } @@ -1583,9 +1558,8 @@ impl KbDexDecodeService { data_json.as_str(), ); for decoded_event in &decoded_events { - let persist_result = self - .persist_raydium_cpmm_event(transaction, instruction, decoded_event) - .await; + let persist_result = + self.persist_raydium_cpmm_event(transaction, instruction, decoded_event).await; let persisted_event = match persist_result { Ok(persisted_event) => persisted_event, Err(error) => return Err(error), @@ -1593,7 +1567,7 @@ impl KbDexDecodeService { persisted.push(persisted_event); } } - Ok(persisted) + return Ok(persisted); } async fn persist_raydium_clmm_event( @@ -1609,7 +1583,7 @@ impl KbDexDecodeService { "transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let instruction_id = match instruction.id { Some(instruction_id) => instruction_id, @@ -1618,7 +1592,7 @@ impl KbDexDecodeService { "raydium clmm instruction for transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let event_kind = decoded_event.event_kind().to_string(); let raw_payload_json = match decoded_event.to_payload_json() { @@ -1627,7 +1601,7 @@ impl KbDexDecodeService { return Err(crate::KbError::Json( "cannot serialize decoded raydium clmm payload".to_string(), )); - } + }, }; let payload_json_result = kb_enrich_serialized_dex_decoded_payload( "raydium_clmm", @@ -1684,7 +1658,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded raydium clmm event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value_result = @@ -1696,7 +1670,7 @@ impl KbDexDecodeService { "cannot parse raydium clmm payload after serialization: {}", error ))); - } + }, }; let observation_result = self .persistence @@ -1728,7 +1702,7 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) + return Ok(fetched); } async fn persist_raydium_cpmm_event( @@ -1744,7 +1718,7 @@ impl KbDexDecodeService { "transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let instruction_id = match instruction.id { Some(instruction_id) => instruction_id, @@ -1753,7 +1727,7 @@ impl KbDexDecodeService { "raydium cpmm instruction for transaction '{}' has no internal id", transaction.signature ))); - } + }, }; let event_kind = decoded_event.event_kind().to_string(); let raw_payload_json = match decoded_event.to_payload_json() { @@ -1762,7 +1736,7 @@ impl KbDexDecodeService { return Err(crate::KbError::Json( "cannot serialize decoded raydium cpmm payload".to_string(), )); - } + }, }; let payload_json_result = kb_enrich_serialized_dex_decoded_payload( "raydium_cpmm", @@ -1819,7 +1793,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded raydium cpmm event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value_result = @@ -1831,7 +1805,7 @@ impl KbDexDecodeService { "cannot parse raydium cpmm payload after serialization: {}", error ))); - } + }, }; let observation_result = self .persistence @@ -1863,7 +1837,7 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) + return Ok(fetched); } async fn persist_pump_fun_event( @@ -1929,7 +1903,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -1963,28 +1937,30 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) - } + return Ok(fetched); + }, crate::KbPumpFunDecodedEvent::BuyTrade(event) => { - self.persist_pump_fun_trade_event( - transaction, - event, - "pump_fun.buy", - "signal.dex.pump_fun.buy", - "dex.pump_fun.buy", - ) - .await - } + return self + .persist_pump_fun_trade_event( + transaction, + event, + "pump_fun.buy", + "signal.dex.pump_fun.buy", + "dex.pump_fun.buy", + ) + .await; + }, crate::KbPumpFunDecodedEvent::SellTrade(event) => { - self.persist_pump_fun_trade_event( - transaction, - event, - "pump_fun.sell", - "signal.dex.pump_fun.sell", - "dex.pump_fun.sell", - ) - .await - } + return self + .persist_pump_fun_trade_event( + transaction, + event, + "pump_fun.sell", + "signal.dex.pump_fun.sell", + "dex.pump_fun.sell", + ) + .await; + }, } } @@ -2051,7 +2027,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded pump.fun trade event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -2085,7 +2061,7 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) + return Ok(fetched); } async fn persist_pump_swap_event( @@ -2095,25 +2071,27 @@ impl KbDexDecodeService { ) -> Result { match decoded_event { crate::KbPumpSwapDecodedEvent::BuyTrade(event) => { - self.persist_pump_swap_trade_event( - transaction, - event, - "pump_swap.buy", - "signal.dex.pump_swap.buy", - "dex.pump_swap.buy", - ) - .await - } + return self + .persist_pump_swap_trade_event( + transaction, + event, + "pump_swap.buy", + "signal.dex.pump_swap.buy", + "dex.pump_swap.buy", + ) + .await; + }, crate::KbPumpSwapDecodedEvent::SellTrade(event) => { - self.persist_pump_swap_trade_event( - transaction, - event, - "pump_swap.sell", - "signal.dex.pump_swap.sell", - "dex.pump_swap.sell", - ) - .await - } + return self + .persist_pump_swap_trade_event( + transaction, + event, + "pump_swap.sell", + "signal.dex.pump_swap.sell", + "dex.pump_swap.sell", + ) + .await; + }, } } @@ -2180,7 +2158,7 @@ impl KbDexDecodeService { return Err(crate::KbError::InvalidState( "decoded event disappeared after upsert".to_string(), )); - } + }, }; if !already_present { let payload_value = event.payload_json.clone(); @@ -2214,7 +2192,7 @@ impl KbDexDecodeService { return Err(error); } } - Ok(fetched) + return Ok(fetched); } } @@ -2238,7 +2216,7 @@ fn kb_classify_dex_event_category(event_kind: &str) -> &'static str { if kb_is_dex_trade_event_kind(event_kind) { return "trade"; } - "unknown" + return "unknown"; } // Returns true when the event kind represents a swap-like event. @@ -2255,7 +2233,7 @@ fn kb_is_dex_trade_event_kind(event_kind: &str) -> bool { if event_kind.contains(".swap_") { return true; } - false + return false; } // Returns true when the event kind can directly produce a candle candidate. @@ -2266,7 +2244,7 @@ fn kb_is_dex_candle_candidate_event_kind(event_kind: &str) -> bool { if event_kind.contains("route") { return false; } - kb_is_dex_trade_event_kind(event_kind) + return kb_is_dex_trade_event_kind(event_kind); } // Returns true for liquidity lifecycle changes that must not become candles. @@ -2289,7 +2267,7 @@ fn kb_is_dex_liquidity_event_kind(event_kind: &str) -> bool { if event_kind.contains(".close_position") { return true; } - false + return false; } // Returns true for fee collection events. @@ -2306,7 +2284,7 @@ fn kb_is_dex_fee_event_kind(event_kind: &str) -> bool { if event_kind.contains("collect_fee") { return true; } - false + return false; } // Returns true for reward/incentive events. @@ -2317,7 +2295,7 @@ fn kb_is_dex_reward_event_kind(event_kind: &str) -> bool { if event_kind.contains("emission") { return true; } - false + return false; } // Returns true for pool creation / initialization / migration events. @@ -2337,7 +2315,7 @@ fn kb_is_dex_pool_lifecycle_event_kind(event_kind: &str) -> bool { if event_kind.contains(".migrate") { return true; } - false + return false; } // Returns true for admin/config/permission changes. @@ -2357,7 +2335,7 @@ fn kb_is_dex_admin_event_kind(event_kind: &str) -> bool { if event_kind.contains("update_") { return true; } - false + return false; } // Enriches a decoded payload with non-destructive classification metadata. @@ -2375,7 +2353,7 @@ fn kb_enrich_dex_decoded_payload( let mut object = serde_json::Map::new(); object.insert("rawPayload".to_owned(), other); object - } + }, }; kb_json_insert_string_if_missing(&mut object, "protocolName", protocol_name); kb_json_insert_string_if_missing(&mut object, "eventKind", event_kind); @@ -2392,7 +2370,7 @@ fn kb_enrich_dex_decoded_payload( "route_or_multihop_event_requires_leg_resolution", ); } - serde_json::Value::Object(object) + return serde_json::Value::Object(object); } // Inserts a string JSON property without overriding existing decoded data. @@ -2428,10 +2406,7 @@ fn kb_json_insert_i64_if_missing( if object.contains_key(key) { return; } - object.insert( - key.to_owned(), - serde_json::Value::Number(serde_json::Number::from(value)), - ); + object.insert(key.to_owned(), serde_json::Value::Number(serde_json::Number::from(value))); } fn kb_enrich_and_serialize_dex_decoded_payload( protocol_name: &str, @@ -2441,11 +2416,13 @@ fn kb_enrich_and_serialize_dex_decoded_payload( let enriched_payload = kb_enrich_dex_decoded_payload(protocol_name, event_kind, payload_json); let payload_json_result = serde_json::to_string(&enriched_payload); match payload_json_result { - Ok(payload_json) => Ok(payload_json), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize enriched decoded payload for '{}': {}", - event_kind, error - ))), + Ok(payload_json) => return Ok(payload_json), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize enriched decoded payload for '{}': {}", + event_kind, error + ))); + }, } } @@ -2462,9 +2439,9 @@ fn kb_enrich_serialized_dex_decoded_payload( "cannot parse decoded payload for '{}': {}", event_kind, error ))); - } + }, }; - kb_enrich_and_serialize_dex_decoded_payload(protocol_name, event_kind, payload_value) + return kb_enrich_and_serialize_dex_decoded_payload(protocol_name, event_kind, payload_value); } #[cfg(test)] @@ -2494,7 +2471,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_projected_raydium_transaction( @@ -2666,9 +2643,7 @@ mod tests { let database = make_database().await; seed_projected_raydium_transaction(database.clone(), "sig-dex-decode-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-1") - .await; + let decoded_result = service.decode_transaction_by_signature("sig-dex-decode-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -2684,9 +2659,7 @@ mod tests { let database = make_database().await; seed_projected_pump_fun_transaction(database.clone(), "sig-dex-decode-pump-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-pump-1") - .await; + let decoded_result = service.decode_transaction_by_signature("sig-dex-decode-pump-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -2694,10 +2667,7 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "pump_fun"); assert_eq!(decoded[0].event_kind, "pump_fun.create_v2_token"); - assert_eq!( - decoded[0].pool_account, - Some("BondingCurvePF111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("BondingCurvePF111".to_string())); assert_eq!(decoded[0].token_a_mint, Some("MintPF111".to_string())); } @@ -2706,9 +2676,8 @@ mod tests { let database = make_database().await; seed_projected_pump_swap_transaction(database.clone(), "sig-dex-decode-pumpswap-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-pumpswap-1") - .await; + let decoded_result = + service.decode_transaction_by_signature("sig-dex-decode-pumpswap-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -2717,18 +2686,9 @@ mod tests { assert_eq!(decoded[0].protocol_name, "pump_swap"); assert_eq!(decoded[0].event_kind, "pump_swap.buy"); assert_eq!(decoded[0].pool_account, Some("PumpSwapPool111".to_string())); - assert_eq!( - decoded[0].token_a_mint, - Some("PumpSwapTokenA111".to_string()) - ); - assert_eq!( - decoded[0].token_b_mint, - Some("PumpSwapTokenB111".to_string()) - ); - assert_eq!( - decoded[0].market_account, - Some("PumpSwapPoolV2_111".to_string()) - ); + assert_eq!(decoded[0].token_a_mint, Some("PumpSwapTokenA111".to_string())); + assert_eq!(decoded[0].token_b_mint, Some("PumpSwapTokenB111".to_string())); + assert_eq!(decoded[0].market_account, Some("PumpSwapPoolV2_111".to_string())); } async fn seed_projected_meteora_dbc_transaction( @@ -2792,9 +2752,7 @@ mod tests { let database = make_database().await; seed_projected_meteora_dbc_transaction(database.clone(), "sig-dex-decode-dbc-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-dbc-1") - .await; + let decoded_result = service.decode_transaction_by_signature("sig-dex-decode-dbc-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -2802,22 +2760,13 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "meteora_dbc"); assert_eq!(decoded[0].event_kind, "meteora_dbc.create_pool"); - assert_eq!( - decoded[0].pool_account, - Some("DbcPoolDecode111".to_string()) - ); - assert_eq!( - decoded[0].token_a_mint, - Some("DbcTokenDecode111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("DbcPoolDecode111".to_string())); + assert_eq!(decoded[0].token_a_mint, Some("DbcTokenDecode111".to_string())); assert_eq!( decoded[0].token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - assert_eq!( - decoded[0].market_account, - Some("DbcConfigDecode111".to_string()) - ); + assert_eq!(decoded[0].market_account, Some("DbcConfigDecode111".to_string())); } async fn seed_projected_meteora_damm_v2_transaction( @@ -2883,9 +2832,8 @@ mod tests { seed_projected_meteora_damm_v2_transaction(database.clone(), "sig-dex-decode-dammv2-1") .await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-dammv2-1") - .await; + let decoded_result = + service.decode_transaction_by_signature("sig-dex-decode-dammv2-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -2893,14 +2841,8 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "meteora_damm_v2"); assert_eq!(decoded[0].event_kind, "meteora_damm_v2.create_pool"); - assert_eq!( - decoded[0].pool_account, - Some("DammV2DecodePool111".to_string()) - ); - assert_eq!( - decoded[0].token_a_mint, - Some("DammV2DecodeTokenA111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("DammV2DecodePool111".to_string())); + assert_eq!(decoded[0].token_a_mint, Some("DammV2DecodeTokenA111".to_string())); assert_eq!( decoded[0].token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) @@ -2970,9 +2912,8 @@ mod tests { seed_projected_meteora_damm_v1_transaction(database.clone(), "sig-dex-decode-dammv1-1") .await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-dammv1-1") - .await; + let decoded_result = + service.decode_transaction_by_signature("sig-dex-decode-dammv1-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -2980,14 +2921,8 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "meteora_damm_v1"); assert_eq!(decoded[0].event_kind, "meteora_damm_v1.create_pool"); - assert_eq!( - decoded[0].pool_account, - Some("DammV1DecodePool111".to_string()) - ); - assert_eq!( - decoded[0].token_a_mint, - Some("DammV1DecodeTokenA111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("DammV1DecodePool111".to_string())); + assert_eq!(decoded[0].token_a_mint, Some("DammV1DecodeTokenA111".to_string())); assert_eq!( decoded[0].token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) @@ -3058,9 +2993,7 @@ mod tests { let database = make_database().await; seed_projected_orca_whirlpools_transaction(database.clone(), "sig-dex-decode-orca-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-orca-1") - .await; + let decoded_result = service.decode_transaction_by_signature("sig-dex-decode-orca-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -3068,22 +3001,13 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "orca_whirlpools"); assert_eq!(decoded[0].event_kind, "orca_whirlpools.create_pool"); - assert_eq!( - decoded[0].pool_account, - Some("OrcaDecodePool111".to_string()) - ); - assert_eq!( - decoded[0].token_a_mint, - Some("OrcaDecodeTokenA111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("OrcaDecodePool111".to_string())); + assert_eq!(decoded[0].token_a_mint, Some("OrcaDecodeTokenA111".to_string())); assert_eq!( decoded[0].token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) ); - assert_eq!( - decoded[0].market_account, - Some("OrcaDecodeConfig111".to_string()) - ); + assert_eq!(decoded[0].market_account, Some("OrcaDecodeConfig111".to_string())); } async fn seed_projected_fluxbeam_transaction( @@ -3148,9 +3072,8 @@ mod tests { let database = make_database().await; seed_projected_fluxbeam_transaction(database.clone(), "sig-dex-decode-fluxbeam-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-fluxbeam-1") - .await; + let decoded_result = + service.decode_transaction_by_signature("sig-dex-decode-fluxbeam-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -3158,18 +3081,9 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "fluxbeam"); assert_eq!(decoded[0].event_kind, "fluxbeam.create_pool"); - assert_eq!( - decoded[0].pool_account, - Some("FluxDecodePool111".to_string()) - ); - assert_eq!( - decoded[0].market_account, - Some("FluxDecodeLpMint111".to_string()) - ); - assert_eq!( - decoded[0].token_a_mint, - Some("FluxDecodeTokenA111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("FluxDecodePool111".to_string())); + assert_eq!(decoded[0].market_account, Some("FluxDecodeLpMint111".to_string())); + assert_eq!(decoded[0].token_a_mint, Some("FluxDecodeTokenA111".to_string())); assert_eq!( decoded[0].token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) @@ -3237,9 +3151,8 @@ mod tests { let database = make_database().await; seed_projected_dexlab_transaction(database.clone(), "sig-dex-decode-dexlab-1").await; let service = crate::KbDexDecodeService::new(database.clone()); - let decoded_result = service - .decode_transaction_by_signature("sig-dex-decode-dexlab-1") - .await; + let decoded_result = + service.decode_transaction_by_signature("sig-dex-decode-dexlab-1").await; let decoded = match decoded_result { Ok(decoded) => decoded, Err(error) => panic!("decode must succeed: {}", error), @@ -3247,14 +3160,8 @@ mod tests { assert_eq!(decoded.len(), 1); assert_eq!(decoded[0].protocol_name, "dexlab"); assert_eq!(decoded[0].event_kind, "dexlab.create_pool"); - assert_eq!( - decoded[0].pool_account, - Some("DexlabDecodePool111".to_string()) - ); - assert_eq!( - decoded[0].token_a_mint, - Some("DexlabDecodeTokenA111".to_string()) - ); + assert_eq!(decoded[0].pool_account, Some("DexlabDecodePool111".to_string())); + assert_eq!(decoded[0].token_a_mint, Some("DexlabDecodeTokenA111".to_string())); assert_eq!( decoded[0].token_b_mint, Some("So11111111111111111111111111111111111111112".to_string()) @@ -3263,32 +3170,13 @@ mod tests { #[test] fn classifies_swap_events_as_trade_candidates() { - assert_eq!( - super::kb_classify_dex_event_category("raydium_cpmm.swap_base_input"), - "trade" - ); - assert_eq!( - super::kb_classify_dex_event_category("raydium_cpmm.swap_base_output"), - "trade" - ); - assert_eq!( - super::kb_classify_dex_event_category("raydium_clmm.swap"), - "trade" - ); - assert_eq!( - super::kb_classify_dex_event_category("raydium_clmm.swap_v2"), - "trade" - ); - assert_eq!( - super::kb_classify_dex_event_category("pump_fun.buy"), - "trade" - ); - assert!(super::kb_is_dex_trade_event_kind( - "raydium_cpmm.swap_base_input" - )); - assert!(super::kb_is_dex_candle_candidate_event_kind( - "raydium_cpmm.swap_base_input" - )); + assert_eq!(super::kb_classify_dex_event_category("raydium_cpmm.swap_base_input"), "trade"); + assert_eq!(super::kb_classify_dex_event_category("raydium_cpmm.swap_base_output"), "trade"); + assert_eq!(super::kb_classify_dex_event_category("raydium_clmm.swap"), "trade"); + assert_eq!(super::kb_classify_dex_event_category("raydium_clmm.swap_v2"), "trade"); + assert_eq!(super::kb_classify_dex_event_category("pump_fun.buy"), "trade"); + assert!(super::kb_is_dex_trade_event_kind("raydium_cpmm.swap_base_input")); + assert!(super::kb_is_dex_candle_candidate_event_kind("raydium_cpmm.swap_base_input")); } #[test] @@ -3297,9 +3185,7 @@ mod tests { super::kb_classify_dex_event_category("raydium_clmm.swap_router_base_in"), "trade" ); - assert!(super::kb_is_dex_trade_event_kind( - "raydium_clmm.swap_router_base_in" - )); + assert!(super::kb_is_dex_trade_event_kind("raydium_clmm.swap_router_base_in")); assert!(!super::kb_is_dex_candle_candidate_event_kind( "raydium_clmm.swap_router_base_in" )); @@ -3345,7 +3231,7 @@ mod tests { Some(object) => object, None => { panic!("expected enriched payload object"); - } + }, }; assert_eq!( object.get("eventCategory"), @@ -3357,18 +3243,10 @@ mod tests { ); assert_eq!( object.get("eventKind"), - Some(&serde_json::Value::String( - "raydium_cpmm.swap_base_input".to_owned() - )) - ); - assert_eq!( - object.get("tradeCandidate"), - Some(&serde_json::Value::Bool(true)) - ); - assert_eq!( - object.get("candleCandidate"), - Some(&serde_json::Value::Bool(true)) + Some(&serde_json::Value::String("raydium_cpmm.swap_base_input".to_owned())) ); + assert_eq!(object.get("tradeCandidate"), Some(&serde_json::Value::Bool(true))); + assert_eq!(object.get("candleCandidate"), Some(&serde_json::Value::Bool(true))); } #[test] @@ -3384,24 +3262,12 @@ mod tests { Some(object) => object, None => { panic!("expected enriched payload object"); - } + }, }; - assert_eq!( - object.get("rawPayload"), - Some(&serde_json::Value::String("raw".to_owned())) - ); - assert_eq!( - object.get("eventCategory"), - Some(&serde_json::Value::String("fee".to_owned())) - ); - assert_eq!( - object.get("tradeCandidate"), - Some(&serde_json::Value::Bool(false)) - ); - assert_eq!( - object.get("candleCandidate"), - Some(&serde_json::Value::Bool(false)) - ); + assert_eq!(object.get("rawPayload"), Some(&serde_json::Value::String("raw".to_owned()))); + assert_eq!(object.get("eventCategory"), Some(&serde_json::Value::String("fee".to_owned()))); + assert_eq!(object.get("tradeCandidate"), Some(&serde_json::Value::Bool(false))); + assert_eq!(object.get("candleCandidate"), Some(&serde_json::Value::Bool(false))); assert_eq!( object.get("skipTradeReason"), Some(&serde_json::Value::String("non_trade_event".to_owned())) diff --git a/kb_lib/src/dex_detect.rs b/kb_lib/src/dex_detect.rs index 82a2fed..1a5152e 100644 --- a/kb_lib/src/dex_detect.rs +++ b/kb_lib/src/dex_detect.rs @@ -34,10 +34,7 @@ impl KbDexDetectService { /// Creates a new DEX detection service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Detects business-level DEX objects from one transaction signature. @@ -58,7 +55,7 @@ impl KbDexDetectService { "cannot detect dex objects from unknown transaction '{}'", signature ))); - } + }, }; let transaction_id_option = transaction.id; let transaction_id = match transaction_id_option { @@ -68,7 +65,7 @@ impl KbDexDetectService { "transaction '{}' has no internal id", signature ))); - } + }, }; let decoded_events_result = crate::list_dex_decoded_events_by_transaction_id( self.database.as_ref(), @@ -84,9 +81,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "raydium_amm_v4" && decoded_event.event_kind == "raydium_amm_v4.initialize2_pool" { - let detect_result = self - .detect_raydium_initialize2_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_raydium_initialize2_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -97,9 +93,8 @@ impl KbDexDetectService { && (decoded_event.event_kind == "raydium_cpmm.swap_base_input" || decoded_event.event_kind == "raydium_cpmm.swap_base_output") { - let detect_result = self - .detect_raydium_cpmm_trade(&transaction, decoded_event) - .await; + let detect_result = + self.detect_raydium_cpmm_trade(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -109,9 +104,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "raydium_clmm" && decoded_event.event_kind == "raydium_clmm.swap_v2" { - let detect_result = self - .detect_raydium_clmm_trade(&transaction, decoded_event) - .await; + let detect_result = + self.detect_raydium_clmm_trade(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -121,9 +115,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "pump_fun" && decoded_event.event_kind == "pump_fun.create_v2_token" { - let detect_result = self - .detect_pump_fun_create_v2_token(&transaction, decoded_event) - .await; + let detect_result = + self.detect_pump_fun_create_v2_token(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -133,9 +126,7 @@ impl KbDexDetectService { if decoded_event.protocol_name == "pump_fun" && decoded_event.event_kind == "pump_fun.buy" { - let detect_result = self - .detect_pump_fun_trade(&transaction, decoded_event) - .await; + let detect_result = self.detect_pump_fun_trade(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -145,9 +136,7 @@ impl KbDexDetectService { if decoded_event.protocol_name == "pump_fun" && decoded_event.event_kind == "pump_fun.sell" { - let detect_result = self - .detect_pump_fun_trade(&transaction, decoded_event) - .await; + let detect_result = self.detect_pump_fun_trade(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -157,9 +146,7 @@ impl KbDexDetectService { if decoded_event.protocol_name == "pump_swap" && decoded_event.event_kind == "pump_swap.buy" { - let detect_result = self - .detect_pump_swap_trade(&transaction, decoded_event) - .await; + let detect_result = self.detect_pump_swap_trade(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -169,9 +156,7 @@ impl KbDexDetectService { if decoded_event.protocol_name == "pump_swap" && decoded_event.event_kind == "pump_swap.sell" { - let detect_result = self - .detect_pump_swap_trade(&transaction, decoded_event) - .await; + let detect_result = self.detect_pump_swap_trade(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -181,9 +166,7 @@ impl KbDexDetectService { if decoded_event.protocol_name == "meteora_dbc" && decoded_event.event_kind == "meteora_dbc.create_pool" { - let detect_result = self - .detect_meteora_dbc_pool(&transaction, decoded_event) - .await; + let detect_result = self.detect_meteora_dbc_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -193,9 +176,7 @@ impl KbDexDetectService { if decoded_event.protocol_name == "meteora_dbc" && decoded_event.event_kind == "meteora_dbc.swap" { - let detect_result = self - .detect_meteora_dbc_pool(&transaction, decoded_event) - .await; + let detect_result = self.detect_meteora_dbc_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -205,9 +186,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "meteora_damm_v2" && decoded_event.event_kind == "meteora_damm_v2.create_pool" { - let detect_result = self - .detect_meteora_damm_v2_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_meteora_damm_v2_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -217,9 +197,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "meteora_damm_v2" && decoded_event.event_kind == "meteora_damm_v2.swap" { - let detect_result = self - .detect_meteora_damm_v2_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_meteora_damm_v2_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -229,9 +208,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "meteora_damm_v1" && decoded_event.event_kind == "meteora_damm_v1.create_pool" { - let detect_result = self - .detect_meteora_damm_v1_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_meteora_damm_v1_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -241,9 +219,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "meteora_damm_v1" && decoded_event.event_kind == "meteora_damm_v1.swap" { - let detect_result = self - .detect_meteora_damm_v1_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_meteora_damm_v1_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -253,9 +230,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "orca_whirlpools" && decoded_event.event_kind == "orca_whirlpools.create_pool" { - let detect_result = self - .detect_orca_whirlpools_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_orca_whirlpools_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -265,9 +241,8 @@ impl KbDexDetectService { if decoded_event.protocol_name == "orca_whirlpools" && decoded_event.event_kind == "orca_whirlpools.swap" { - let detect_result = self - .detect_orca_whirlpools_pool(&transaction, decoded_event) - .await; + let detect_result = + self.detect_orca_whirlpools_pool(&transaction, decoded_event).await; let detect_result = match detect_result { Ok(detect_result) => detect_result, Err(error) => return Err(error), @@ -314,7 +289,7 @@ impl KbDexDetectService { detection_results.push(detect_result); } } - Ok(detection_results) + return Ok(detection_results); } async fn detect_raydium_initialize2_pool( @@ -329,7 +304,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_raydium_dex().await; let dex_id = match dex_id_result { @@ -344,7 +319,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -354,7 +329,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -364,21 +339,13 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let lp_mint = decoded_event.lp_mint.clone(); let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -396,7 +363,7 @@ impl KbDexDetectService { Ok(lp_token_id) => Some(lp_token_id), Err(error) => return Err(error), } - } + }, None => None, }; let existing_pool_result = @@ -416,9 +383,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -431,7 +398,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -451,9 +418,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -467,7 +434,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -530,7 +497,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -576,7 +543,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -585,7 +552,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_pump_fun_create_v2_token( @@ -600,7 +567,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_pump_fun_dex().await; let dex_id = match dex_id_result { @@ -615,7 +582,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_mint_option = decoded_event.token_a_mint.clone(); let token_mint = match token_mint_option { @@ -625,20 +592,13 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let quote_mint = crate::WSOL_MINT_ID.to_string(); let base_is_token_a = kb_choose_base_quote_order(token_mint.as_str(), quote_mint.as_str()); - let base_mint = if base_is_token_a { - token_mint.clone() - } else { - quote_mint.clone() - }; - let quote_mint_ordered = if base_is_token_a { - quote_mint.clone() - } else { - token_mint.clone() - }; + let base_mint = if base_is_token_a { token_mint.clone() } else { quote_mint.clone() }; + let quote_mint_ordered = + if base_is_token_a { quote_mint.clone() } else { token_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -666,9 +626,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -681,7 +641,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -701,9 +661,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -717,7 +677,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -764,7 +724,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -810,7 +770,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -819,7 +779,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_pump_fun_trade( @@ -834,7 +794,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_pump_fun_dex().await; let dex_id = match dex_id_result { @@ -849,7 +809,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -859,7 +819,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -869,20 +829,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -929,9 +881,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -944,7 +896,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -1006,7 +958,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; if created_pool { let signal_result = self @@ -1047,7 +999,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -1056,7 +1008,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_pump_swap_trade( @@ -1071,7 +1023,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_pump_swap_dex().await; let dex_id = match dex_id_result { @@ -1086,7 +1038,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -1096,7 +1048,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -1106,20 +1058,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -1166,9 +1110,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -1181,7 +1125,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -1243,7 +1187,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; if created_pool { let signal_result = self @@ -1284,7 +1228,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -1293,7 +1237,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_meteora_dbc_pool( @@ -1308,7 +1252,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_meteora_dbc_dex().await; let dex_id = match dex_id_result { @@ -1323,7 +1267,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -1333,7 +1277,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -1343,20 +1287,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -1384,9 +1320,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -1399,7 +1335,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -1419,9 +1355,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -1435,7 +1371,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -1482,7 +1418,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -1528,7 +1464,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -1537,7 +1473,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_meteora_damm_v2_pool( @@ -1552,7 +1488,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_meteora_damm_v2_dex().await; let dex_id = match dex_id_result { @@ -1567,7 +1503,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -1577,7 +1513,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -1587,20 +1523,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -1628,9 +1556,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -1643,7 +1571,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -1663,9 +1591,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -1679,7 +1607,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -1726,7 +1654,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -1772,7 +1700,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -1781,7 +1709,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_meteora_damm_v1_pool( @@ -1796,7 +1724,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_meteora_damm_v1_dex().await; let dex_id = match dex_id_result { @@ -1811,7 +1739,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -1821,7 +1749,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -1831,20 +1759,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -1872,9 +1792,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -1887,7 +1807,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -1907,9 +1827,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -1923,7 +1843,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -1970,7 +1890,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -2016,7 +1936,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -2025,7 +1945,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_orca_whirlpools_pool( @@ -2040,7 +1960,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_orca_whirlpools_dex().await; let dex_id = match dex_id_result { @@ -2055,7 +1975,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -2065,7 +1985,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -2075,20 +1995,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -2116,9 +2028,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -2131,7 +2043,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -2151,9 +2063,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -2167,7 +2079,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -2214,7 +2126,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -2260,7 +2172,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -2269,7 +2181,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_fluxbeam_pool( @@ -2284,7 +2196,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_fluxbeam_dex().await; let dex_id = match dex_id_result { @@ -2299,7 +2211,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -2309,7 +2221,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -2319,20 +2231,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -2360,9 +2264,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -2375,7 +2279,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -2395,9 +2299,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -2411,7 +2315,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -2458,7 +2362,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -2504,7 +2408,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -2513,7 +2417,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_dexlab_pool( @@ -2528,7 +2432,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_dexlab_dex().await; let dex_id = match dex_id_result { @@ -2543,7 +2447,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let token_a_mint_option = decoded_event.token_a_mint.clone(); let token_a_mint = match token_a_mint_option { @@ -2553,7 +2457,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let token_b_mint_option = decoded_event.token_b_mint.clone(); let token_b_mint = match token_b_mint_option { @@ -2563,20 +2467,12 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let base_is_token_a = kb_choose_base_quote_order(token_a_mint.as_str(), token_b_mint.as_str()); - let base_mint = if base_is_token_a { - token_a_mint.clone() - } else { - token_b_mint.clone() - }; - let quote_mint = if base_is_token_a { - token_b_mint.clone() - } else { - token_a_mint.clone() - }; + let base_mint = if base_is_token_a { token_a_mint.clone() } else { token_b_mint.clone() }; + let quote_mint = if base_is_token_a { token_b_mint.clone() } else { token_a_mint.clone() }; let base_token_id_result = self.ensure_token(base_mint.as_str()).await; let base_token_id = match base_token_id_result { Ok(base_token_id) => base_token_id, @@ -2604,9 +2500,9 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, } - } + }, None => { let pool_dto = crate::KbPoolDto::new( dex_id, @@ -2619,7 +2515,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -2639,9 +2535,9 @@ impl KbDexDetectService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, } - } + }, None => { let pair_dto = crate::KbPairDto::new( dex_id, @@ -2655,7 +2551,7 @@ impl KbDexDetectService { Ok(pair_id) => pair_id, Err(error) => return Err(error), } - } + }, }; let upsert_base_pool_token_result = crate::upsert_pool_token( self.database.as_ref(), @@ -2702,7 +2598,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -2748,7 +2644,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -2757,9 +2653,9 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } - + async fn detect_raydium_clmm_trade( &self, transaction: &crate::KbChainTransactionDto, @@ -2771,7 +2667,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_raydium_clmm_dex().await; let dex_id = match dex_id_result { @@ -2785,7 +2681,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let base_mint = match decoded_event.token_a_mint.clone() { Some(base_mint) => base_mint, @@ -2794,7 +2690,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let quote_mint = match decoded_event.token_b_mint.clone() { Some(quote_mint) => quote_mint, @@ -2803,7 +2699,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -2837,7 +2733,7 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, }, None => { let pool_dto = crate::KbPoolDto::new( @@ -2851,7 +2747,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -2915,7 +2811,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; if created_pool { let signal_result = self @@ -2956,7 +2852,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -2965,7 +2861,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn detect_raydium_cpmm_trade( @@ -2979,7 +2875,7 @@ impl KbDexDetectService { return Err(crate::KbError::InvalidState( "decoded dex event has no internal id".to_string(), )); - } + }, }; let dex_id_result = self.ensure_raydium_cpmm_dex().await; let dex_id = match dex_id_result { @@ -2993,7 +2889,7 @@ impl KbDexDetectService { "decoded event '{}' has no pool_account", decoded_event_id ))); - } + }, }; let base_mint = match decoded_event.token_a_mint.clone() { Some(base_mint) => base_mint, @@ -3002,7 +2898,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_a_mint", decoded_event_id ))); - } + }, }; let quote_mint = match decoded_event.token_b_mint.clone() { Some(quote_mint) => quote_mint, @@ -3011,7 +2907,7 @@ impl KbDexDetectService { "decoded event '{}' has no token_b_mint", decoded_event_id ))); - } + }, }; let payload_value_result = kb_parse_payload_json(decoded_event.payload_json.as_str()); let payload_value = match payload_value_result { @@ -3045,7 +2941,7 @@ impl KbDexDetectService { "pool '{}' has no internal id", pool.address ))); - } + }, }, None => { let pool_dto = crate::KbPoolDto::new( @@ -3059,7 +2955,7 @@ impl KbDexDetectService { Ok(pool_id) => pool_id, Err(error) => return Err(error), } - } + }, }; let existing_pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; @@ -3121,7 +3017,7 @@ impl KbDexDetectService { Ok(listing_id) => Some(listing_id), Err(error) => return Err(error), } - } + }, }; if created_pool { let signal_result = self @@ -3162,7 +3058,7 @@ impl KbDexDetectService { return Err(error); } } - Ok(crate::KbDexPoolDetectionResult { + return Ok(crate::KbDexPoolDetectionResult { decoded_event_id, dex_id, pool_id, @@ -3171,7 +3067,7 @@ impl KbDexDetectService { created_pool, created_pair, created_listing, - }) + }); } async fn ensure_raydium_cpmm_dex(&self) -> Result { @@ -3182,10 +3078,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "raydium_cpmm dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "raydium_cpmm dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3195,8 +3093,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3208,10 +3106,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "raydium_clmm dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "raydium_clmm dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3221,8 +3121,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3234,10 +3134,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "dexlab dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "dexlab dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3247,8 +3149,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3260,10 +3162,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "fluxbeam dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "fluxbeam dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3273,8 +3177,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3286,10 +3190,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "orca_whirlpools dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "orca_whirlpools dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3299,8 +3205,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3312,10 +3218,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "meteora_damm_v1 dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "meteora_damm_v1 dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3325,8 +3233,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3338,10 +3246,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "meteora_damm_v2 dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "meteora_damm_v2 dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3351,8 +3261,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3364,10 +3274,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "meteora_dbc dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "meteora_dbc dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3377,8 +3289,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3390,10 +3302,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "pump_swap dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "pump_swap dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3403,8 +3317,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3416,10 +3330,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "pump_fun dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "pump_fun dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3429,8 +3345,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3442,10 +3358,12 @@ impl KbDexDetectService { }; match dex_option { Some(dex) => match dex.id { - Some(dex_id) => Ok(dex_id), - None => Err(crate::KbError::InvalidState( - "raydium dex has no internal id".to_string(), - )), + Some(dex_id) => return Ok(dex_id), + None => { + return Err(crate::KbError::InvalidState( + "raydium dex has no internal id".to_string(), + )); + }, }, None => { let dex_dto = crate::KbDexDto::new( @@ -3455,8 +3373,8 @@ impl KbDexDetectService { None, true, ); - crate::upsert_dex(self.database.as_ref(), &dex_dto).await - } + return crate::upsert_dex(self.database.as_ref(), &dex_dto).await; + }, } } @@ -3468,11 +3386,13 @@ impl KbDexDetectService { }; match token_option { Some(token) => match token.id { - Some(token_id) => Ok(token_id), - None => Err(crate::KbError::InvalidState(format!( - "token '{}' has no internal id", - mint - ))), + Some(token_id) => return Ok(token_id), + None => { + return Err(crate::KbError::InvalidState(format!( + "token '{}' has no internal id", + mint + ))); + }, }, None => { let token_dto = crate::KbTokenDto::new( @@ -3483,8 +3403,8 @@ impl KbDexDetectService { crate::SPL_TOKEN_PROGRAM_ID.to_string(), kb_is_quote_mint(mint), ); - crate::upsert_token(self.database.as_ref(), &token_dto).await - } + return crate::upsert_token(self.database.as_ref(), &token_dto).await; + }, } } @@ -3505,7 +3425,7 @@ impl KbDexDetectService { None, None, ); - crate::upsert_pool_listing(self.database.as_ref(), &listing_dto).await + return crate::upsert_pool_listing(self.database.as_ref(), &listing_dto).await; } async fn record_detection_signal( @@ -3530,7 +3450,8 @@ impl KbDexDetectService { Ok(observation_id) => observation_id, Err(error) => return Err(error), }; - self.persistence + return self + .persistence .record_signal(&crate::KbDetectionSignalInput::new( signal_kind.to_string(), severity, @@ -3539,12 +3460,12 @@ impl KbDexDetectService { None, payload, )) - .await + .await; } } fn kb_is_quote_mint(mint: &str) -> bool { - mint == "So11111111111111111111111111111111111111112" + return mint == "So11111111111111111111111111111111111111112"; } fn kb_choose_base_quote_order(token_a_mint: &str, token_b_mint: &str) -> bool { @@ -3556,7 +3477,7 @@ fn kb_choose_base_quote_order(token_a_mint: &str, token_b_mint: &str) -> bool { if token_b_is_quote && !token_a_is_quote { return true; } - true + return true; } fn kb_build_pair_symbol( @@ -3567,8 +3488,10 @@ fn kb_build_pair_symbol( let quote_symbol = kb_symbol_hint_from_mint(quote_mint); match (base_symbol, quote_symbol) { - (Some(base_symbol), Some(quote_symbol)) => Some(format!("{base_symbol}/{quote_symbol}")), - _ => None, + (Some(base_symbol), Some(quote_symbol)) => { + return Some(format!("{base_symbol}/{quote_symbol}")); + }, + _ => return None, } } @@ -3576,17 +3499,19 @@ fn kb_symbol_hint_from_mint(mint: &str) -> std::option::Option Result { let parse_result = serde_json::from_str::(payload_json); match parse_result { - Ok(value) => Ok(value), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse dex decoded event payload_json '{}': {}", - payload_json, error - ))), + Ok(value) => return Ok(value), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse dex decoded event payload_json '{}': {}", + payload_json, error + ))); + }, } } @@ -3606,7 +3531,7 @@ fn kb_extract_string_from_array_index( if text.is_empty() { return None; } - Some(text.to_string()) + return Some(text.to_string()); } fn kb_extract_pump_fun_vault_addresses( @@ -3627,7 +3552,7 @@ fn kb_extract_pump_fun_vault_addresses( }; let token_a_vault_address = kb_extract_string_from_array_index(accounts_array, 4); let token_b_native_address = kb_extract_string_from_array_index(accounts_array, 3); - (token_a_vault_address, token_b_native_address) + return (token_a_vault_address, token_b_native_address); } fn kb_extract_pump_swap_vault_addresses( @@ -3648,7 +3573,7 @@ fn kb_extract_pump_swap_vault_addresses( }; let token_a_vault_address = kb_extract_string_from_array_index(accounts_array, 7); let token_b_vault_address = kb_extract_string_from_array_index(accounts_array, 8); - (token_a_vault_address, token_b_vault_address) + return (token_a_vault_address, token_b_vault_address); } fn kb_extract_payload_string_field( @@ -3661,8 +3586,8 @@ fn kb_extract_payload_string_field( None => return None, }; match value.as_str() { - Some(value) => Some(value.to_string()), - None => None, + Some(value) => return Some(value.to_string()), + None => return None, } } @@ -3692,7 +3617,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_decoded_raydium_event( @@ -3764,9 +3689,8 @@ mod tests { let database = make_database().await; seed_decoded_raydium_event(database.clone(), "sig-dex-detect-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), @@ -3820,9 +3744,7 @@ mod tests { let database = make_database().await; seed_decoded_raydium_event(database.clone(), "sig-dex-detect-2").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let first_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-2") - .await; + let first_result = detect_service.detect_transaction_by_signature("sig-dex-detect-2").await; let first_results = match first_result { Ok(first_results) => first_results, Err(error) => panic!("first dex detect must succeed: {}", error), @@ -3831,9 +3753,8 @@ mod tests { assert!(first_results[0].created_pool); assert!(first_results[0].created_pair); assert!(first_results[0].created_listing); - let second_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-2") - .await; + let second_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-2").await; let second_results = match second_result { Ok(second_results) => second_results, Err(error) => panic!("second dex detect must succeed: {}", error), @@ -3923,9 +3844,8 @@ mod tests { let database = make_database().await; seed_decoded_pump_fun_event(database.clone(), "sig-dex-detect-pump-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-pump-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-pump-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), @@ -4188,9 +4108,8 @@ mod tests { let database = make_database().await; seed_decoded_meteora_dbc_event(database.clone(), "sig-dex-detect-dbc-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-dbc-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-dbc-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), @@ -4307,9 +4226,8 @@ mod tests { let database = make_database().await; seed_decoded_meteora_damm_v2_event(database.clone(), "sig-dex-detect-dammv2-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-dammv2-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-dammv2-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), @@ -4427,9 +4345,8 @@ mod tests { let database = make_database().await; seed_decoded_meteora_damm_v1_event(database.clone(), "sig-dex-detect-dammv1-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-dammv1-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-dammv1-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), @@ -4549,9 +4466,8 @@ mod tests { let database = make_database().await; seed_decoded_orca_whirlpools_event(database.clone(), "sig-dex-detect-orca-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-orca-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-orca-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), @@ -4786,9 +4702,8 @@ mod tests { let database = make_database().await; seed_decoded_dexlab_event(database.clone(), "sig-dex-detect-dexlab-1").await; let detect_service = crate::KbDexDetectService::new(database.clone()); - let detect_result = detect_service - .detect_transaction_by_signature("sig-dex-detect-dexlab-1") - .await; + let detect_result = + detect_service.detect_transaction_by_signature("sig-dex-detect-dexlab-1").await; let results = match detect_result { Ok(results) => results, Err(error) => panic!("dex detect must succeed: {}", error), diff --git a/kb_lib/src/error.rs b/kb_lib/src/error.rs index a7950d0..2313a65 100644 --- a/kb_lib/src/error.rs +++ b/kb_lib/src/error.rs @@ -33,36 +33,18 @@ pub enum KbError { impl std::fmt::Display for KbError { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Config(message) => { - write!(formatter, "configuration error: {message}") - } - Self::Io(message) => { - write!(formatter, "io error: {message}") - } - Self::Json(message) => { - write!(formatter, "json error: {message}") - } - Self::Tracing(message) => { - write!(formatter, "tracing error: {message}") - } - Self::Http(message) => { - write!(formatter, "http error: {message}") - } - Self::Ws(message) => { - write!(formatter, "websocket error: {message}") - } - Self::Db(message) => { - write!(formatter, "db error: {}", message) - } - Self::InvalidState(message) => { - write!(formatter, "invalid state: {message}") - } - Self::NotConnected(message) => { - write!(formatter, "not connected: {message}") - } + Self::Config(message) => return write!(formatter, "configuration error: {message}"), + Self::Io(message) => return write!(formatter, "io error: {message}"), + Self::Json(message) => return write!(formatter, "json error: {message}"), + Self::Tracing(message) => return write!(formatter, "tracing error: {message}"), + Self::Http(message) => return write!(formatter, "http error: {message}"), + Self::Ws(message) => return write!(formatter, "websocket error: {message}"), + Self::Db(message) => return write!(formatter, "db error: {}", message), + Self::InvalidState(message) => return write!(formatter, "invalid state: {message}"), + Self::NotConnected(message) => return write!(formatter, "not connected: {message}"), Self::NotImplemented(message) => { - write!(formatter, "not implemented: {message}") - } + return write!(formatter, "not implemented: {message}"); + }, } } } diff --git a/kb_lib/src/http_client.rs b/kb_lib/src/http_client.rs index ecb8eae..014d593 100644 --- a/kb_lib/src/http_client.rs +++ b/kb_lib/src/http_client.rs @@ -31,23 +31,25 @@ impl KbJsonRpcHttpRequest { method: std::string::String, params: std::vec::Vec, ) -> Self { - Self { + return Self { jsonrpc: "2.0".to_string(), id: serde_json::Value::from(id), method, params, - } + }; } /// Serializes the request into a compact JSON string. pub fn to_json_string(&self) -> Result { let text_result = serde_json::to_string(self); match text_result { - Ok(text) => Ok(text), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize http json-rpc request '{}': {error}", - self.method - ))), + Ok(text) => return Ok(text), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize http json-rpc request '{}': {error}", + self.method + ))); + }, } } } @@ -127,10 +129,10 @@ struct KbHttpTokenBucket { impl KbHttpTokenBucket { fn new(burst_capacity: u32) -> Self { - Self { + return Self { tokens: burst_capacity as f64, last_refill_at: std::time::Instant::now(), - } + }; } } @@ -151,7 +153,7 @@ struct KbHttpRuntimeState { impl KbHttpRuntimeState { fn new(endpoint: &crate::KbHttpEndpointConfig) -> Self { - Self { + return Self { lifecycle: KbHttpEndpointLifecycleState::Active, general_bucket: KbHttpTokenBucket::new(endpoint.burst_capacity), send_transaction_bucket: KbHttpTokenBucket::new(kb_http_effective_burst_capacity( @@ -162,7 +164,7 @@ impl KbHttpRuntimeState { endpoint, KbHttpMethodClass::HeavyRead, )), - } + }; } } @@ -249,18 +251,10 @@ impl HttpClient { Err(error) => return Err(error), }; let builder = reqwest::Client::builder() - .connect_timeout(std::time::Duration::from_millis( - endpoint.connect_timeout_ms, - )) - .timeout(std::time::Duration::from_millis( - endpoint.request_timeout_ms, - )) + .connect_timeout(std::time::Duration::from_millis(endpoint.connect_timeout_ms)) + .timeout(std::time::Duration::from_millis(endpoint.request_timeout_ms)) .pool_max_idle_per_host(endpoint.max_idle_connections_per_host) - .user_agent(format!( - "{}/{}", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_VERSION") - )); + .user_agent(format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"))); let client_result = builder.build(); let client = match client_result { Ok(client) => client, @@ -269,9 +263,9 @@ impl HttpClient { "cannot build reqwest client for endpoint '{}': {error}", endpoint.name ))); - } + }, }; - Ok(Self { + return Ok(Self { endpoint: endpoint.clone(), resolved_url, client, @@ -282,22 +276,22 @@ impl HttpClient { concurrency_limiter: std::sync::Arc::new(tokio::sync::Semaphore::new( endpoint.max_concurrent_requests_per_endpoint, )), - }) + }); } /// Returns the endpoint name. pub fn endpoint_name(&self) -> &str { - &self.endpoint.name + return &self.endpoint.name; } /// Returns the resolved endpoint URL. pub fn endpoint_url(&self) -> &str { - &self.resolved_url + return &self.resolved_url; } /// Returns the endpoint configuration. pub fn endpoint_config(&self) -> &crate::KbHttpEndpointConfig { - &self.endpoint + return &self.endpoint; } /// Returns whether this endpoint supports the requested logical role. @@ -305,33 +299,31 @@ impl HttpClient { if required_role.trim().is_empty() { return true; } - self.endpoint.roles.iter().any(|role| role == required_role) + return self.endpoint.roles.iter().any(|role| return role == required_role); } /// Returns the currently available concurrency slots for this endpoint. pub fn available_concurrency_slots(&self) -> usize { - self.concurrency_limiter.available_permits() + return self.concurrency_limiter.available_permits(); } /// Returns the next request identifier and increments the internal counter. pub fn next_request_id(&self) -> u64 { - self.next_request_id - .fetch_add(1, std::sync::atomic::Ordering::Relaxed) + return self.next_request_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } /// Returns the current local endpoint status. pub async fn endpoint_status(&self) -> KbHttpEndpointStatus { let mut runtime_guard = self.runtime.lock().await; kb_http_normalize_runtime_lifecycle(&mut runtime_guard); - match runtime_guard.lifecycle.clone() { - KbHttpEndpointLifecycleState::Active => KbHttpEndpointStatus::Active, - KbHttpEndpointLifecycleState::Disabled => KbHttpEndpointStatus::Disabled, + KbHttpEndpointLifecycleState::Active => return KbHttpEndpointStatus::Active, + KbHttpEndpointLifecycleState::Disabled => return KbHttpEndpointStatus::Disabled, KbHttpEndpointLifecycleState::PausedUntil(deadline) => { let now = std::time::Instant::now(); if deadline <= now { runtime_guard.lifecycle = KbHttpEndpointLifecycleState::Active; - KbHttpEndpointStatus::Active + return KbHttpEndpointStatus::Active; } else { let remaining = deadline.duration_since(now); let remaining_ms_u128 = remaining.as_millis(); @@ -340,9 +332,9 @@ impl HttpClient { } else { remaining_ms_u128 as u64 }; - KbHttpEndpointStatus::Paused { remaining_ms } + return KbHttpEndpointStatus::Paused { remaining_ms }; } - } + }, } } @@ -357,10 +349,7 @@ impl HttpClient { /// Resumes this endpoint if it is paused. pub async fn resume(&self) { let mut runtime_guard = self.runtime.lock().await; - if matches!( - runtime_guard.lifecycle, - KbHttpEndpointLifecycleState::PausedUntil(_) - ) { + if matches!(runtime_guard.lifecycle, KbHttpEndpointLifecycleState::PausedUntil(_)) { runtime_guard.lifecycle = KbHttpEndpointLifecycleState::Active; } } @@ -379,7 +368,7 @@ impl HttpClient { /// Classifies one HTTP JSON-RPC method. pub fn classify_method(method: &str) -> KbHttpMethodClass { - kb_http_classify_method(method) + return kb_http_classify_method(method); } /// Executes one JSON-RPC request and returns the success envelope. @@ -390,7 +379,7 @@ impl HttpClient { ) -> Result { let request_id = self.next_request_id(); let request = KbJsonRpcHttpRequest::new_with_u64_id(request_id, method, params); - self.execute_json_rpc_request_object(&request).await + return self.execute_json_rpc_request_object(&request).await; } /// Executes one prebuilt JSON-RPC request object. @@ -399,9 +388,7 @@ impl HttpClient { request: &KbJsonRpcHttpRequest, ) -> Result { let method_class = kb_http_classify_method(&request.method); - let rate_limit_result = self - .acquire_rate_limit_slot_for_method_class(method_class) - .await; + let rate_limit_result = self.acquire_rate_limit_slot_for_method_class(method_class).await; if let Err(error) = rate_limit_result { return Err(error); } @@ -418,7 +405,7 @@ impl HttpClient { "cannot acquire concurrency slot for endpoint '{}' method '{}': {}", self.endpoint.name, request.method, error ))); - } + }, }; tracing::debug!( endpoint_name = %self.endpoint.name, @@ -442,13 +429,10 @@ impl HttpClient { "http request failed for endpoint '{}' method '{}': {error}", self.endpoint.name, request.method ))); - } + }, }; let status = response.status(); - let retry_after_header = response - .headers() - .get(reqwest::header::RETRY_AFTER) - .cloned(); + let retry_after_header = response.headers().get(reqwest::header::RETRY_AFTER).cloned(); let text_result = response.text().await; let text = match text_result { Ok(text) => text, @@ -457,16 +441,14 @@ impl HttpClient { "cannot read http response body for endpoint '{}' method '{}': {error}", self.endpoint.name, request.method ))); - } + }, }; if status.as_u16() == 429 { - let pause_duration_ms = match retry_after_header - .as_ref() - .and_then(kb_http_retry_after_to_pause_ms) - { - Some(retry_after_ms) => retry_after_ms, - None => self.endpoint.pause_after_http_429_ms.unwrap_or(1500), - }; + let pause_duration_ms = + match retry_after_header.as_ref().and_then(kb_http_retry_after_to_pause_ms) { + Some(retry_after_ms) => retry_after_ms, + None => self.endpoint.pause_after_http_429_ms.unwrap_or(1500), + }; self.pause_for(pause_duration_ms).await; return Err(crate::KbError::Http(format!( "http status 429 returned by endpoint '{}' method '{}'; endpoint paused for {} ms; body='{}'", @@ -491,14 +473,16 @@ impl HttpClient { Err(error) => return Err(error), }; match parsed_response { - KbJsonRpcHttpResponse::Success(success_response) => Ok(success_response), - KbJsonRpcHttpResponse::Error(error_response) => Err(crate::KbError::Http(format!( - "json-rpc http error on endpoint '{}' method '{}': code={} message={}", - self.endpoint.name, - request.method, - error_response.error.code, - error_response.error.message - ))), + KbJsonRpcHttpResponse::Success(success_response) => return Ok(success_response), + KbJsonRpcHttpResponse::Error(error_response) => { + return Err(crate::KbError::Http(format!( + "json-rpc http error on endpoint '{}' method '{}': code={} message={}", + self.endpoint.name, + request.method, + error_response.error.code, + error_response.error.message + ))); + }, } } @@ -513,7 +497,7 @@ impl HttpClient { Ok(raw_response) => raw_response, Err(error) => return Err(error), }; - Ok(raw_response.result) + return Ok(raw_response.result); } /// Executes one JSON-RPC request and decodes `result` into `T`. @@ -532,43 +516,49 @@ impl HttpClient { }; let typed_result = serde_json::from_value::(raw_value); match typed_result { - Ok(value) => Ok(value), - Err(error) => Err(crate::KbError::Json(format!( - "cannot decode typed http json-rpc result: {error}" - ))), + Ok(value) => return Ok(value), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot decode typed http json-rpc result: {error}" + ))); + }, } } /// Raw helper for `getHealth`. pub async fn get_health_raw(&self) -> Result { - self.execute_json_rpc_result_raw("getHealth".to_string(), std::vec::Vec::new()) - .await + return self + .execute_json_rpc_result_raw("getHealth".to_string(), std::vec::Vec::new()) + .await; } /// Typed helper for `getHealth`. pub async fn get_health(&self) -> Result { - self.execute_json_rpc_request_typed::( - "getHealth".to_string(), - std::vec::Vec::new(), - ) - .await + return self + .execute_json_rpc_request_typed::( + "getHealth".to_string(), + std::vec::Vec::new(), + ) + .await; } /// Raw helper for `getVersion`. pub async fn get_version_raw(&self) -> Result { - self.execute_json_rpc_result_raw("getVersion".to_string(), std::vec::Vec::new()) - .await + return self + .execute_json_rpc_result_raw("getVersion".to_string(), std::vec::Vec::new()) + .await; } /// Typed helper for `getVersion`. pub async fn get_version( &self, ) -> Result { - self.execute_json_rpc_request_typed::( - "getVersion".to_string(), - std::vec::Vec::new(), - ) - .await + return self + .execute_json_rpc_request_typed::( + "getVersion".to_string(), + std::vec::Vec::new(), + ) + .await; } /// Raw helper for `getSlot`. @@ -577,8 +567,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_optional_config_only_params(config); - self.execute_json_rpc_result_raw("getSlot".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getSlot".to_string(), params).await; } /// Typed helper for `getSlot`. @@ -592,8 +581,7 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_optional_config_only_params(config_value); - self.execute_json_rpc_request_typed::("getSlot".to_string(), params) - .await + return self.execute_json_rpc_request_typed::("getSlot".to_string(), params).await; } /// Raw helper for `getBlockHeight`. @@ -602,8 +590,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_optional_config_only_params(config); - self.execute_json_rpc_result_raw("getBlockHeight".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getBlockHeight".to_string(), params).await; } /// Typed helper for `getBlockHeight`. @@ -617,8 +604,9 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_optional_config_only_params(config_value); - self.execute_json_rpc_request_typed::("getBlockHeight".to_string(), params) - .await + return self + .execute_json_rpc_request_typed::("getBlockHeight".to_string(), params) + .await; } /// Raw helper for `getLatestBlockhash`. @@ -627,8 +615,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_optional_config_only_params(config); - self.execute_json_rpc_result_raw("getLatestBlockhash".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getLatestBlockhash".to_string(), params).await; } /// Typed helper for `getLatestBlockhash`. @@ -646,12 +633,12 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_optional_config_only_params(config_value); - self.execute_json_rpc_request_typed::< + return self.execute_json_rpc_request_typed::< solana_rpc_client_api::response::Response< solana_rpc_client_api::response::RpcBlockhash, >, >("getLatestBlockhash".to_string(), params) - .await + .await; } /// Raw helper for `getBalance`. @@ -661,8 +648,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_first_string_optional_config_params(address, config); - self.execute_json_rpc_result_raw("getBalance".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getBalance".to_string(), params).await; } /// Typed helper for `getBalance`. @@ -677,11 +663,12 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_first_string_optional_config_params(address, config_value); - self.execute_json_rpc_request_typed::>( - "getBalance".to_string(), - params, - ) - .await + return self + .execute_json_rpc_request_typed::>( + "getBalance".to_string(), + params, + ) + .await; } /// Raw helper for `getAccountInfo`. @@ -691,8 +678,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_first_string_optional_config_params(address, config); - self.execute_json_rpc_result_raw("getAccountInfo".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getAccountInfo".to_string(), params).await; } /// Typed helper for `getAccountInfo`. @@ -712,10 +698,11 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_first_string_optional_config_params(address, config_value); - self.execute_json_rpc_request_typed::, - >>("getAccountInfo".to_string(), params) - .await + return self + .execute_json_rpc_request_typed::, + >>("getAccountInfo".to_string(), params) + .await; } /// Raw helper for `getProgramAccounts`. @@ -725,8 +712,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_first_string_optional_config_params(program_id, config); - self.execute_json_rpc_result_raw("getProgramAccounts".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getProgramAccounts".to_string(), params).await; } /// Raw helper for `getSignaturesForAddress`. @@ -736,8 +722,9 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_first_string_optional_config_params(address, config); - self.execute_json_rpc_result_raw("getSignaturesForAddress".to_string(), params) - .await + return self + .execute_json_rpc_result_raw("getSignaturesForAddress".to_string(), params) + .await; } /// Typed helper for `getSignaturesForAddress`. @@ -756,10 +743,11 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_first_string_optional_config_params(address, config_value); - self.execute_json_rpc_request_typed::>("getSignaturesForAddress".to_string(), params) - .await + return self + .execute_json_rpc_request_typed::>("getSignaturesForAddress".to_string(), params) + .await; } /// Raw helper for `getTransaction`. @@ -769,8 +757,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_first_string_optional_config_params(signature, config); - self.execute_json_rpc_result_raw("getTransaction".to_string(), params) - .await + return self.execute_json_rpc_result_raw("getTransaction".to_string(), params).await; } /// Typed helper for `getTransaction`. @@ -788,10 +775,10 @@ impl HttpClient { Err(error) => return Err(error), }; let params = kb_build_first_string_optional_config_params(signature, config_value); - self.execute_json_rpc_request_typed::< + return self.execute_json_rpc_request_typed::< std::option::Option, >("getTransaction".to_string(), params) - .await + .await; } /// Raw helper for `sendTransaction`. @@ -801,8 +788,7 @@ impl HttpClient { config: std::option::Option, ) -> Result { let params = kb_build_first_string_optional_config_params(encoded_transaction, config); - self.execute_json_rpc_result_raw("sendTransaction".to_string(), params) - .await + return self.execute_json_rpc_result_raw("sendTransaction".to_string(), params).await; } /// Typed helper for `sendTransaction`. @@ -819,11 +805,12 @@ impl HttpClient { }; let params = kb_build_first_string_optional_config_params(encoded_transaction, config_value); - self.execute_json_rpc_request_typed::( - "sendTransaction".to_string(), - params, - ) - .await + return self + .execute_json_rpc_request_typed::( + "sendTransaction".to_string(), + params, + ) + .await; } async fn acquire_rate_limit_slot_for_method_class( @@ -840,7 +827,7 @@ impl HttpClient { "http endpoint '{}' is disabled", self.endpoint.name ))); - } + }, KbHttpEndpointLifecycleState::PausedUntil(deadline) => { let now = std::time::Instant::now(); if deadline > now { @@ -853,7 +840,7 @@ impl HttpClient { method_class, ) } - } + }, KbHttpEndpointLifecycleState::Active => kb_http_consume_rate_limit_token( &self.endpoint, &mut runtime_guard, @@ -864,13 +851,13 @@ impl HttpClient { match wait_duration_option { Some(wait_duration) => { tokio::time::sleep(wait_duration).await; - } + }, None => { break; - } + }, } } - Ok(()) + return Ok(()); } } @@ -882,12 +869,10 @@ pub fn parse_kb_json_rpc_http_response_text( let value = match value_result { Ok(value) => value, Err(error) => { - return Err(crate::KbError::Json(format!( - "cannot parse http json-rpc text: {error}" - ))); - } + return Err(crate::KbError::Json(format!("cannot parse http json-rpc text: {error}"))); + }, }; - parse_kb_json_rpc_http_response_value(&value) + return parse_kb_json_rpc_http_response_value(&value); } /// Parses one JSON-RPC HTTP response value. @@ -901,7 +886,7 @@ pub fn parse_kb_json_rpc_http_response_value( return Err(crate::KbError::Json( "http json-rpc payload must be a JSON object".to_string(), )); - } + }, }; let jsonrpc_value_option = object.get("jsonrpc"); let jsonrpc_value = match jsonrpc_value_option { @@ -910,7 +895,7 @@ pub fn parse_kb_json_rpc_http_response_value( return Err(crate::KbError::Json( "http json-rpc payload is missing 'jsonrpc'".to_string(), )); - } + }, }; let jsonrpc_string_option = jsonrpc_value.as_str(); let jsonrpc_string = match jsonrpc_string_option { @@ -919,7 +904,7 @@ pub fn parse_kb_json_rpc_http_response_value( return Err(crate::KbError::Json( "http json-rpc field 'jsonrpc' must be a string".to_string(), )); - } + }, }; if jsonrpc_string != "2.0" { return Err(crate::KbError::Json(format!( @@ -943,14 +928,14 @@ pub fn parse_kb_json_rpc_http_response_value( let response_result = serde_json::from_value::(value.clone()); return match response_result { Ok(response) => Ok(KbJsonRpcHttpResponse::Error(response)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse http json-rpc error response: {error}" - ))), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse http json-rpc error response: {error}" + ))); + }, }; } - Err(crate::KbError::Json( - "unsupported http json-rpc response shape".to_string(), - )) + return Err(crate::KbError::Json("unsupported http json-rpc response shape".to_string())); } fn kb_build_optional_config_only_params( @@ -960,7 +945,7 @@ fn kb_build_optional_config_only_params( if let Some(config) = config { params.push(config); } - params + return params; } fn kb_build_first_string_optional_config_params( @@ -971,7 +956,7 @@ fn kb_build_first_string_optional_config_params( if let Some(config) = config { params.push(config); } - params + return params; } fn kb_serialize_optional_json_value( @@ -985,14 +970,16 @@ where Some(value) => { let value_result = serde_json::to_value(value); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize {}: {error}", - label - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize {}: {error}", + label + ))); + }, } - } - None => Ok(None), + }, + None => return Ok(None), } } @@ -1003,7 +990,7 @@ fn kb_http_classify_method(method: &str) -> KbHttpMethodClass { if method == "getProgramAccounts" || method == "getLargestAccounts" { return KbHttpMethodClass::HeavyRead; } - KbHttpMethodClass::GeneralRpc + return KbHttpMethodClass::GeneralRpc; } fn kb_http_effective_requests_per_second( @@ -1011,13 +998,15 @@ fn kb_http_effective_requests_per_second( method_class: KbHttpMethodClass, ) -> u32 { match method_class { - KbHttpMethodClass::GeneralRpc => endpoint.requests_per_second, - KbHttpMethodClass::SendTransaction => endpoint - .send_transaction_requests_per_second - .unwrap_or(endpoint.requests_per_second), - KbHttpMethodClass::HeavyRead => endpoint - .heavy_requests_per_second - .unwrap_or(endpoint.requests_per_second), + KbHttpMethodClass::GeneralRpc => return endpoint.requests_per_second, + KbHttpMethodClass::SendTransaction => { + return endpoint + .send_transaction_requests_per_second + .unwrap_or(endpoint.requests_per_second); + }, + KbHttpMethodClass::HeavyRead => { + return endpoint.heavy_requests_per_second.unwrap_or(endpoint.requests_per_second); + }, } } @@ -1026,13 +1015,13 @@ fn kb_http_effective_burst_capacity( method_class: KbHttpMethodClass, ) -> u32 { match method_class { - KbHttpMethodClass::GeneralRpc => endpoint.burst_capacity, - KbHttpMethodClass::SendTransaction => endpoint - .send_transaction_burst_capacity - .unwrap_or(endpoint.burst_capacity), - KbHttpMethodClass::HeavyRead => endpoint - .heavy_burst_capacity - .unwrap_or(endpoint.burst_capacity), + KbHttpMethodClass::GeneralRpc => return endpoint.burst_capacity, + KbHttpMethodClass::SendTransaction => { + return endpoint.send_transaction_burst_capacity.unwrap_or(endpoint.burst_capacity); + }, + KbHttpMethodClass::HeavyRead => { + return endpoint.heavy_burst_capacity.unwrap_or(endpoint.burst_capacity); + }, } } @@ -1077,7 +1066,7 @@ fn kb_http_consume_rate_limit_token( } let missing_tokens = 1.0 - bucket.tokens; let wait_seconds = missing_tokens / requests_per_second as f64; - Some(std::time::Duration::from_secs_f64(wait_seconds.max(0.001))) + return Some(std::time::Duration::from_secs_f64(wait_seconds.max(0.001))); } fn kb_http_retry_after_to_pause_ms( @@ -1088,7 +1077,7 @@ fn kb_http_retry_after_to_pause_ms( Ok(header_text) => header_text.trim(), Err(_) => { return None; - } + }, }; let seconds_result = header_text.parse::(); if let Ok(seconds) = seconds_result { @@ -1099,14 +1088,14 @@ fn kb_http_retry_after_to_pause_ms( Ok(parsed_date) => parsed_date.with_timezone(&chrono::Utc), Err(_) => { return None; - } + }, }; let now = chrono::Utc::now(); let delta_ms = parsed_date.signed_duration_since(now).num_milliseconds(); if delta_ms <= 0 { return Some(0); } - Some(delta_ms as u64) + return Some(delta_ms as u64); } fn kb_http_shorten_text(input: &str, max_chars: usize) -> std::string::String { @@ -1115,7 +1104,7 @@ fn kb_http_shorten_text(input: &str, max_chars: usize) -> std::string::String { return input.to_string(); } let shortened: std::string::String = input.chars().take(max_chars).collect(); - format!("{shortened} …[truncated {} chars]", char_count - max_chars) + return format!("{shortened} …[truncated {} chars]", char_count - max_chars); } #[cfg(test)] @@ -1317,16 +1306,16 @@ mod tests { } } }); - Self { + return Self { url: format!("http://{}", local_addr), shutdown_tx: Some(shutdown_tx), observed_methods, - } + }; } async fn observed_methods_snapshot(&self) -> std::vec::Vec { let observed_methods_guard = self.observed_methods.lock().await; - observed_methods_guard.clone() + return observed_methods_guard.clone(); } async fn shutdown(mut self) { @@ -1337,7 +1326,7 @@ mod tests { } fn make_http_endpoint(url: std::string::String) -> crate::KbHttpEndpointConfig { - crate::KbHttpEndpointConfig { + return crate::KbHttpEndpointConfig { name: "test_http".to_string(), enabled: true, provider: "test".to_string(), @@ -1355,7 +1344,7 @@ mod tests { max_idle_connections_per_host: 4, pause_after_http_429_ms: Some(1500), max_concurrent_requests_per_endpoint: 2, - } + }; } #[test] @@ -1368,10 +1357,10 @@ mod tests { crate::KbJsonRpcHttpResponse::Success(response) => { assert_eq!(response.result, serde_json::Value::String("ok".to_string())); assert_eq!(response.id, serde_json::Value::from(1u64)); - } + }, other => { panic!("unexpected response: {other:?}"); - } + }, } } @@ -1385,10 +1374,10 @@ mod tests { crate::KbJsonRpcHttpResponse::Error(response) => { assert_eq!(response.error.code, -32601); assert_eq!(response.error.message, "Method not found"); - } + }, other => { panic!("unexpected response: {other:?}"); - } + }, } } @@ -1429,10 +1418,10 @@ mod tests { match paused_status { crate::KbHttpEndpointStatus::Paused { remaining_ms } => { assert!(remaining_ms > 0); - } + }, other => { panic!("unexpected status: {other:?}"); - } + }, } client.resume().await; let resumed_status = client.endpoint_status().await; @@ -1452,17 +1441,12 @@ mod tests { let client = crate::HttpClient::new(endpoint).expect("client creation must succeed"); let health = client.get_health().await.expect("get_health must succeed"); assert_eq!(health, "ok".to_string()); - let version = client - .get_version() - .await - .expect("get_version must succeed"); + let version = client.get_version().await.expect("get_version must succeed"); assert_eq!(version.solana_core, "2.2.3".to_string()); let slot = client.get_slot(None).await.expect("get_slot must succeed"); assert_eq!(slot, 424242u64); - let block_height = client - .get_block_height(None) - .await - .expect("get_block_height must succeed"); + let block_height = + client.get_block_height(None).await.expect("get_block_height must succeed"); assert_eq!(block_height, 919191u64); let latest_blockhash = client .get_latest_blockhash(None) @@ -1500,35 +1484,15 @@ mod tests { .expect("send_transaction must succeed"); assert_eq!(sent_signature, "signature-test".to_string()); let observed_methods = server.observed_methods_snapshot().await; - assert!(observed_methods.iter().any(|method| method == "getHealth")); - assert!(observed_methods.iter().any(|method| method == "getVersion")); - assert!(observed_methods.iter().any(|method| method == "getSlot")); - assert!( - observed_methods - .iter() - .any(|method| method == "getBlockHeight") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "getLatestBlockhash") - ); - assert!(observed_methods.iter().any(|method| method == "getBalance")); - assert!( - observed_methods - .iter() - .any(|method| method == "getSignaturesForAddress") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "getTransaction") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "sendTransaction") - ); + assert!(observed_methods.iter().any(|method| return method == "getHealth")); + assert!(observed_methods.iter().any(|method| return method == "getVersion")); + assert!(observed_methods.iter().any(|method| return method == "getSlot")); + assert!(observed_methods.iter().any(|method| return method == "getBlockHeight")); + assert!(observed_methods.iter().any(|method| return method == "getLatestBlockhash")); + assert!(observed_methods.iter().any(|method| return method == "getBalance")); + assert!(observed_methods.iter().any(|method| return method == "getSignaturesForAddress")); + assert!(observed_methods.iter().any(|method| return method == "getTransaction")); + assert!(observed_methods.iter().any(|method| return method == "sendTransaction")); server.shutdown().await; } @@ -1538,18 +1502,9 @@ mod tests { let endpoint = make_http_endpoint(server.url.clone()); let client = crate::HttpClient::new(endpoint).expect("client creation must succeed"); - let _ = client - .get_health_raw() - .await - .expect("get_health_raw must succeed"); - let _ = client - .get_version_raw() - .await - .expect("get_version_raw must succeed"); - let _ = client - .get_slot_raw(None) - .await - .expect("get_slot_raw must succeed"); + let _ = client.get_health_raw().await.expect("get_health_raw must succeed"); + let _ = client.get_version_raw().await.expect("get_version_raw must succeed"); + let _ = client.get_slot_raw(None).await.expect("get_slot_raw must succeed"); let _ = client .get_block_height_raw(None) .await @@ -1586,45 +1541,17 @@ mod tests { .await .expect("send_transaction_raw must succeed"); let observed_methods = server.observed_methods_snapshot().await; - assert!(observed_methods.iter().any(|method| method == "getHealth")); - assert!(observed_methods.iter().any(|method| method == "getVersion")); - assert!(observed_methods.iter().any(|method| method == "getSlot")); - assert!( - observed_methods - .iter() - .any(|method| method == "getBlockHeight") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "getLatestBlockhash") - ); - assert!(observed_methods.iter().any(|method| method == "getBalance")); - assert!( - observed_methods - .iter() - .any(|method| method == "getAccountInfo") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "getProgramAccounts") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "getSignaturesForAddress") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "getTransaction") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "sendTransaction") - ); + assert!(observed_methods.iter().any(|method| return method == "getHealth")); + assert!(observed_methods.iter().any(|method| return method == "getVersion")); + assert!(observed_methods.iter().any(|method| return method == "getSlot")); + assert!(observed_methods.iter().any(|method| return method == "getBlockHeight")); + assert!(observed_methods.iter().any(|method| return method == "getLatestBlockhash")); + assert!(observed_methods.iter().any(|method| return method == "getBalance")); + assert!(observed_methods.iter().any(|method| return method == "getAccountInfo")); + assert!(observed_methods.iter().any(|method| return method == "getProgramAccounts")); + assert!(observed_methods.iter().any(|method| return method == "getSignaturesForAddress")); + assert!(observed_methods.iter().any(|method| return method == "getTransaction")); + assert!(observed_methods.iter().any(|method| return method == "sendTransaction")); server.shutdown().await; } @@ -1641,10 +1568,10 @@ mod tests { match paused_status { crate::KbHttpEndpointStatus::Paused { remaining_ms } => { assert!(remaining_ms > 0); - } + }, other => { panic!("unexpected status after 429: {other:?}"); - } + }, } tokio::time::sleep(std::time::Duration::from_millis(1100)).await; let resumed_status = client.endpoint_status().await; @@ -1663,10 +1590,10 @@ mod tests { match error { crate::KbError::Http(message) => { assert!(message.contains("is disabled")); - } + }, other => { panic!("unexpected error: {other:?}"); - } + }, } } @@ -1683,10 +1610,10 @@ mod tests { match error { crate::KbError::Http(message) => { assert!(message.contains("Method not found")); - } + }, other => { panic!("unexpected error: {other:?}"); - } + }, } server.shutdown().await; } diff --git a/kb_lib/src/http_pool.rs b/kb_lib/src/http_pool.rs index ab99eb4..b559a77 100644 --- a/kb_lib/src/http_pool.rs +++ b/kb_lib/src/http_pool.rs @@ -44,10 +44,10 @@ impl HttpEndpointPool { "http endpoint pool requires at least one client".to_string(), )); } - Ok(Self { + return Ok(Self { clients, next_index: std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0)), - }) + }); } /// Creates a pool from endpoint configurations. @@ -66,22 +66,22 @@ impl HttpEndpointPool { }; clients.push(client); } - Self::new(clients) + return Self::new(clients); } /// Creates a pool from the global configuration. pub fn from_config(config: &crate::KbConfig) -> Result { - Self::from_endpoint_configs(config.solana.http_endpoints.clone()) + return Self::from_endpoint_configs(config.solana.http_endpoints.clone()); } /// Returns the number of pooled clients. pub fn len(&self) -> usize { - self.clients.len() + return self.clients.len(); } /// Returns whether the pool is empty. pub fn is_empty(&self) -> bool { - self.clients.is_empty() + return self.clients.is_empty(); } /// Returns a live snapshot of pooled endpoints. @@ -94,7 +94,7 @@ impl HttpEndpointPool { crate::KbHttpEndpointStatus::Disabled => ("Disabled".to_string(), None), crate::KbHttpEndpointStatus::Paused { remaining_ms } => { ("Paused".to_string(), Some(remaining_ms)) - } + }, }; snapshots.push(KbHttpPoolClientSnapshot { endpoint_name: client.endpoint_name().to_string(), @@ -106,7 +106,7 @@ impl HttpEndpointPool { available_concurrency_slots: client.available_concurrency_slots(), }); } - snapshots + return snapshots; } /// Selects one client for a role and method. @@ -134,13 +134,13 @@ impl HttpEndpointPool { match status { crate::KbHttpEndpointStatus::Active => { active_indices.push(index); - } + }, crate::KbHttpEndpointStatus::Paused { .. } => { paused_count += 1; - } + }, crate::KbHttpEndpointStatus::Disabled => { disabled_count += 1; - } + }, } index += 1; } @@ -150,9 +150,7 @@ impl HttpEndpointPool { required_role, method, paused_count, disabled_count, role_mismatch_count ))); } - let rotation_seed = self - .next_index - .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + let rotation_seed = self.next_index.fetch_add(1, std::sync::atomic::Ordering::Relaxed); let active_len = active_indices.len(); let mut offset = 0usize; while offset < active_len { @@ -164,7 +162,7 @@ impl HttpEndpointPool { offset += 1; } let fallback_index = active_indices[rotation_seed % active_len]; - Ok(self.clients[fallback_index].clone()) + return Ok(self.clients[fallback_index].clone()); } /// Executes one raw JSON-RPC request through the pool. @@ -174,14 +172,12 @@ impl HttpEndpointPool { method: std::string::String, params: std::vec::Vec, ) -> Result { - let client_result = self - .select_client_for_role_and_method(required_role, &method) - .await; + let client_result = self.select_client_for_role_and_method(required_role, &method).await; let client = match client_result { Ok(client) => client, Err(error) => return Err(error), }; - client.execute_json_rpc_result_raw(method, params).await + return client.execute_json_rpc_result_raw(method, params).await; } /// Executes one typed JSON-RPC request through the pool. @@ -194,28 +190,25 @@ impl HttpEndpointPool { where T: serde::de::DeserializeOwned, { - let client_result = self - .select_client_for_role_and_method(required_role, &method) - .await; + let client_result = self.select_client_for_role_and_method(required_role, &method).await; let client = match client_result { Ok(client) => client, Err(error) => return Err(error), }; - client - .execute_json_rpc_request_typed::(method, params) - .await + return client.execute_json_rpc_request_typed::(method, params).await; } /// Executes `getHealth` through the pool. pub async fn get_health_for_role( &self, required_role: &str, ) -> Result { - self.execute_json_rpc_request_typed_for_role::( - required_role, - "getHealth".to_string(), - std::vec::Vec::new(), - ) - .await + return self + .execute_json_rpc_request_typed_for_role::( + required_role, + "getHealth".to_string(), + std::vec::Vec::new(), + ) + .await; } /// Executes `getSlot` through the pool. @@ -231,12 +224,13 @@ impl HttpEndpointPool { Err(error) => return Err(error), }; let params = kb_pool_build_optional_config_only_params(config_value); - self.execute_json_rpc_request_typed_for_role::( - required_role, - "getSlot".to_string(), - params, - ) - .await + return self + .execute_json_rpc_request_typed_for_role::( + required_role, + "getSlot".to_string(), + params, + ) + .await; } /// Executes `sendTransaction` through the pool. @@ -254,12 +248,13 @@ impl HttpEndpointPool { }; let params = kb_pool_build_first_string_optional_config_params(encoded_transaction, config_value); - self.execute_json_rpc_request_typed_for_role::( - required_role, - "sendTransaction".to_string(), - params, - ) - .await + return self + .execute_json_rpc_request_typed_for_role::( + required_role, + "sendTransaction".to_string(), + params, + ) + .await; } /// Executes `getTransaction` through the pool and returns the raw result value. @@ -269,14 +264,29 @@ impl HttpEndpointPool { signature: std::string::String, config: std::option::Option, ) -> Result { - let client_result = self - .select_client_for_role_and_method(required_role, "getTransaction") - .await; + let client_result = + self.select_client_for_role_and_method(required_role, "getTransaction").await; let client = match client_result { Ok(client) => client, Err(error) => return Err(error), }; - client.get_transaction_raw(signature, config).await + return client.get_transaction_raw(signature, config).await; + } + + /// Executes `getAccountInfo` through the pool and returns the raw result value. + pub async fn get_account_info_raw_for_role( + &self, + required_role: &str, + address: std::string::String, + config: std::option::Option, + ) -> Result { + let client_result = + self.select_client_for_role_and_method(required_role, "getAccountInfo").await; + let client = match client_result { + Ok(client) => client, + Err(error) => return Err(error), + }; + return client.get_account_info_raw(address, config).await; } /// Executes `getProgramAccounts` through the pool and returns the raw result value. @@ -293,7 +303,7 @@ impl HttpEndpointPool { Ok(client) => client, Err(error) => return Err(error), }; - client.get_program_accounts_raw(program_id, config).await + return client.get_program_accounts_raw(program_id, config).await; } /// Executes `getSignaturesForAddress` through the pool and returns the raw result value. @@ -310,7 +320,7 @@ impl HttpEndpointPool { Ok(client) => client, Err(error) => return Err(error), }; - client.get_signatures_for_address_raw(address, config).await + return client.get_signatures_for_address_raw(address, config).await; } /// Executes typed `getSignaturesForAddress` through the pool. @@ -330,7 +340,7 @@ impl HttpEndpointPool { Ok(client) => client, Err(error) => return Err(error), }; - client.get_signatures_for_address(address, config).await + return client.get_signatures_for_address(address, config).await; } } @@ -342,7 +352,7 @@ fn kb_pool_build_optional_config_only_params( if let Some(config) = config { params.push(config); } - params + return params; } fn kb_pool_build_first_string_optional_config_params( @@ -350,11 +360,10 @@ fn kb_pool_build_first_string_optional_config_params( config: std::option::Option, ) -> std::vec::Vec { let mut params = vec![serde_json::Value::String(first)]; - if let Some(config) = config { params.push(config); } - params + return params; } fn kb_pool_serialize_optional_json_value( @@ -368,14 +377,16 @@ where Some(value) => { let value_result = serde_json::to_value(value); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize {}: {error}", - label - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize {}: {error}", + label + ))); + }, } - } - None => Ok(None), + }, + None => return Ok(None), } } @@ -472,11 +483,12 @@ mod tests { } } }); - Self { + return Self { url: format!("http://{}", local_addr), shutdown_tx: Some(shutdown_tx), - } + }; } + async fn shutdown(mut self) { if let Some(shutdown_tx) = self.shutdown_tx.take() { let _ = shutdown_tx.send(()); @@ -490,7 +502,7 @@ mod tests { url: std::string::String, roles: std::vec::Vec, ) -> crate::KbHttpEndpointConfig { - crate::KbHttpEndpointConfig { + return crate::KbHttpEndpointConfig { name: name.to_string(), enabled: true, provider: provider.to_string(), @@ -508,7 +520,7 @@ mod tests { max_idle_connections_per_host: 4, max_concurrent_requests_per_endpoint: 2, pause_after_http_429_ms: Some(1500), - } + }; } #[tokio::test] @@ -595,12 +607,8 @@ mod tests { .expect("pool creation must succeed"); let snapshots = pool.snapshot().await; assert_eq!(snapshots.len(), 2); - assert!(snapshots.iter().any(|snapshot| snapshot.status == "Active")); - assert!( - snapshots - .iter() - .any(|snapshot| snapshot.status == "Disabled") - ); + assert!(snapshots.iter().any(|snapshot| return snapshot.status == "Active")); + assert!(snapshots.iter().any(|snapshot| return snapshot.status == "Disabled")); } #[tokio::test] @@ -669,18 +677,16 @@ mod tests { client_a.disable().await; let pool = crate::HttpEndpointPool::new(vec![client_a]).expect("pool creation must succeed"); - let result = pool - .select_client_for_role_and_method("http_queries", "getSlot") - .await; + let result = pool.select_client_for_role_and_method("http_queries", "getSlot").await; assert!(result.is_err()); let error = result.expect_err("selection must fail"); match error { crate::KbError::Http(message) => { assert!(message.contains("no active http endpoint available")); - } + }, other => { panic!("unexpected error: {other:?}"); - } + }, } } } diff --git a/kb_lib/src/json_rpc_ws.rs b/kb_lib/src/json_rpc_ws.rs index 7206ffa..74a322c 100644 --- a/kb_lib/src/json_rpc_ws.rs +++ b/kb_lib/src/json_rpc_ws.rs @@ -29,23 +29,25 @@ impl KbJsonRpcWsRequest { method: std::string::String, params: std::vec::Vec, ) -> Self { - Self { + return Self { jsonrpc: "2.0".to_string(), id: serde_json::Value::from(id), method, params, - } + }; } /// Converts the request into a JSON value. pub fn to_value(&self) -> Result { let value_result = serde_json::to_value(self); match value_result { - Ok(value) => Ok(value), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize websocket json-rpc request '{}': {error}", - self.method - ))), + Ok(value) => return Ok(value), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize websocket json-rpc request '{}': {error}", + self.method + ))); + }, } } @@ -53,11 +55,13 @@ impl KbJsonRpcWsRequest { pub fn to_json_string(&self) -> Result { let text_result = serde_json::to_string(self); match text_result { - Ok(text) => Ok(text), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize websocket json-rpc request '{}': {error}", - self.method - ))), + Ok(text) => return Ok(text), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize websocket json-rpc request '{}': {error}", + self.method + ))); + }, } } } @@ -130,9 +134,9 @@ impl KbJsonRpcWsIncomingMessage { /// Returns a short human-readable kind label. pub fn kind_name(&self) -> &'static str { match self { - Self::SuccessResponse(_) => "success_response", - Self::ErrorResponse(_) => "error_response", - Self::Notification(_) => "notification", + Self::SuccessResponse(_) => return "success_response", + Self::ErrorResponse(_) => return "error_response", + Self::Notification(_) => return "notification", } } } @@ -143,7 +147,7 @@ impl KbJsonRpcWsIncomingMessage { /// trimming left-side whitespace. pub fn kb_is_probable_json_rpc_object_text(text: &str) -> bool { let trimmed = text.trim_start(); - trimmed.starts_with('{') + return trimmed.starts_with('{'); } /// Parses a raw text message into a JSON-RPC incoming message. @@ -160,10 +164,9 @@ pub fn parse_kb_json_rpc_ws_incoming_text( return Err(crate::KbError::Json(format!( "cannot parse websocket json-rpc text: {error}" ))); - } + }, }; - - parse_kb_json_rpc_ws_incoming_value(&value) + return parse_kb_json_rpc_ws_incoming_value(&value); } /// Parses a JSON value into a JSON-RPC incoming message. @@ -179,7 +182,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value( return Err(crate::KbError::Json( "json-rpc websocket payload must be a JSON object".to_string(), )); - } + }, }; let jsonrpc_value_option = object.get("jsonrpc"); let jsonrpc_value = match jsonrpc_value_option { @@ -188,7 +191,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value( return Err(crate::KbError::Json( "json-rpc websocket payload is missing 'jsonrpc'".to_string(), )); - } + }, }; let jsonrpc_string_option = jsonrpc_value.as_str(); let jsonrpc_string = match jsonrpc_string_option { @@ -197,7 +200,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value( return Err(crate::KbError::Json( "json-rpc websocket field 'jsonrpc' must be a string".to_string(), )); - } + }, }; if jsonrpc_string != "2.0" { return Err(crate::KbError::Json(format!( @@ -218,7 +221,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value( return Err(crate::KbError::Json(format!( "cannot parse websocket json-rpc notification: {error}" ))); - } + }, }; return Ok(KbJsonRpcWsIncomingMessage::Notification(notification)); } @@ -230,7 +233,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value( return Err(crate::KbError::Json(format!( "cannot parse websocket json-rpc success response: {error}" ))); - } + }, }; return Ok(KbJsonRpcWsIncomingMessage::SuccessResponse(response)); } @@ -242,13 +245,11 @@ pub fn parse_kb_json_rpc_ws_incoming_value( return Err(crate::KbError::Json(format!( "cannot parse websocket json-rpc error response: {error}" ))); - } + }, }; return Ok(KbJsonRpcWsIncomingMessage::ErrorResponse(response)); } - Err(crate::KbError::Json( - "unsupported websocket json-rpc message shape".to_string(), - )) + return Err(crate::KbError::Json("unsupported websocket json-rpc message shape".to_string())); } #[cfg(test)] @@ -260,18 +261,10 @@ mod tests { "slotSubscribe".to_string(), std::vec::Vec::new(), ); - let value = request - .to_value() - .expect("request value serialization must succeed"); - assert_eq!( - value["jsonrpc"], - serde_json::Value::String("2.0".to_string()) - ); + let value = request.to_value().expect("request value serialization must succeed"); + assert_eq!(value["jsonrpc"], serde_json::Value::String("2.0".to_string())); assert_eq!(value["id"], serde_json::Value::from(7u64)); - assert_eq!( - value["method"], - serde_json::Value::String("slotSubscribe".to_string()) - ); + assert_eq!(value["method"], serde_json::Value::String("slotSubscribe".to_string())); assert_eq!(value["params"], serde_json::Value::Array(vec![])); } @@ -284,10 +277,10 @@ mod tests { assert_eq!(response.jsonrpc, "2.0"); assert_eq!(response.result, serde_json::Value::from(42u64)); assert_eq!(response.id, serde_json::Value::from(3u64)); - } + }, other => { panic!("unexpected parsed message: {other:?}"); - } + }, } } @@ -303,10 +296,10 @@ mod tests { assert_eq!(response.error.message, "Method not found"); assert_eq!(response.error.data, None); assert_eq!(response.id, serde_json::Value::from(9u64)); - } + }, other => { panic!("unexpected parsed message: {other:?}"); - } + }, } } @@ -319,22 +312,17 @@ mod tests { assert_eq!(notification.jsonrpc, "2.0"); assert_eq!(notification.method, "slotNotification"); assert_eq!(notification.params.subscription, 17); - assert_eq!( - notification.params.result["slot"], - serde_json::Value::from(3u64) - ); - } + assert_eq!(notification.params.result["slot"], serde_json::Value::from(3u64)); + }, other => { panic!("unexpected parsed message: {other:?}"); - } + }, } } #[test] fn probable_json_rpc_object_text_detects_object() { - assert!(crate::kb_is_probable_json_rpc_object_text( - " {\"jsonrpc\":\"2.0\"}" - )); + assert!(crate::kb_is_probable_json_rpc_object_text(" {\"jsonrpc\":\"2.0\"}")); assert!(!crate::kb_is_probable_json_rpc_object_text("hello")); } } diff --git a/kb_lib/src/launch_origin.rs b/kb_lib/src/launch_origin.rs index c661a0e..890d022 100644 --- a/kb_lib/src/launch_origin.rs +++ b/kb_lib/src/launch_origin.rs @@ -30,10 +30,7 @@ impl KbLaunchOriginService { /// Creates a new launch-origin service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Ensures that the built-in `moonit` launch surface exists and returns its id. @@ -51,7 +48,7 @@ impl KbLaunchOriginService { return Err(crate::KbError::InvalidState( "moonit launch surface has no internal id".to_string(), )); - } + }, }, None => { let dto = crate::KbLaunchSurfaceDto::new( @@ -66,7 +63,7 @@ impl KbLaunchOriginService { Ok(surface_id) => surface_id, Err(error) => return Err(error), } - } + }, }; let suffix_key_result = crate::upsert_launch_surface_key( self.database.as_ref(), @@ -80,7 +77,7 @@ impl KbLaunchOriginService { if let Err(error) = suffix_key_result { return Err(error); } - Ok(surface_id) + return Ok(surface_id); } /// Ensures that the built-in `bags` launch surface exists and returns its id. @@ -93,10 +90,12 @@ impl KbLaunchOriginService { }; match existing_option { Some(existing) => match existing.id { - Some(surface_id) => Ok(surface_id), - None => Err(crate::KbError::InvalidState( - "bags launch surface has no internal id".to_string(), - )), + Some(surface_id) => return Ok(surface_id), + None => { + return Err(crate::KbError::InvalidState( + "bags launch surface has no internal id".to_string(), + )); + }, }, None => { let dto = crate::KbLaunchSurfaceDto::new( @@ -105,8 +104,8 @@ impl KbLaunchOriginService { Some("launchpad".to_string()), true, ); - crate::upsert_launch_surface(self.database.as_ref(), &dto).await - } + return crate::upsert_launch_surface(self.database.as_ref(), &dto).await; + }, } } @@ -177,7 +176,7 @@ impl KbLaunchOriginService { return Err(error); } } - Ok(surface_id) + return Ok(surface_id); } /// Attributes one transaction to known launch surfaces from decoded events. @@ -198,7 +197,7 @@ impl KbLaunchOriginService { "cannot attribute unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { Some(transaction_id) => transaction_id, @@ -207,7 +206,7 @@ impl KbLaunchOriginService { "transaction '{}' has no internal id", signature ))); - } + }, }; let ensure_moonit_result = self.ensure_moonit_surface().await; if let Err(error) = ensure_moonit_result { @@ -239,7 +238,7 @@ impl KbLaunchOriginService { return Err(crate::KbError::InvalidState( "decoded event has no internal id".to_string(), )); - } + }, }; let pool_id = match decoded_event.pool_account.clone() { Some(pool_address) => { @@ -254,7 +253,7 @@ impl KbLaunchOriginService { Some(pool) => pool.id, None => None, } - } + }, None => None, }; let pair_id = match pool_id { @@ -269,7 +268,7 @@ impl KbLaunchOriginService { Some(pair) => pair.id, None => None, } - } + }, None => None, }; let existing_result = crate::get_launch_attribution_by_decoded_event_id( @@ -289,7 +288,7 @@ impl KbLaunchOriginService { return Err(crate::KbError::InvalidState( "launch attribution has no internal id".to_string(), )); - } + }, } } else { let dto = crate::KbLaunchAttributionDto::new( @@ -359,7 +358,7 @@ impl KbLaunchOriginService { created_attribution, }); } - Ok(results) + return Ok(results); } async fn match_surface_for_decoded_event( @@ -379,9 +378,8 @@ impl KbLaunchOriginService { if let Some(token_b_mint) = decoded_event.token_b_mint.clone() { candidates.push(("token_mint".to_string(), token_b_mint)); } - let payload_result = serde_json::from_str::( - decoded_event.payload_json.as_str(), - ); + let payload_result = + serde_json::from_str::(decoded_event.payload_json.as_str()); let payload = match payload_result { Ok(payload) => Some(payload), Err(_) => None, @@ -411,11 +409,7 @@ impl KbLaunchOriginService { None => continue, }; let matched_result = self - .build_matched_surface_from_key( - key, - match_kind.clone(), - matched_value.clone(), - ) + .build_matched_surface_from_key(key, match_kind.clone(), matched_value.clone()) .await; let matched_option = match matched_result { Ok(matched_option) => matched_option, @@ -427,11 +421,11 @@ impl KbLaunchOriginService { } let moonit_result = self.match_moonit_by_suffix(decoded_event).await; match moonit_result { - Ok(moonit_result) => Ok(moonit_result), - Err(error) => Err(error), + Ok(moonit_result) => return Ok(moonit_result), + Err(error) => return Err(error), } } - + async fn build_matched_surface_from_key( &self, key: crate::KbLaunchSurfaceKeyDto, @@ -460,7 +454,7 @@ impl KbLaunchOriginService { matched_value, })); } - Ok(None) + return Ok(None); } async fn match_moonit_by_suffix( @@ -504,14 +498,14 @@ impl KbLaunchOriginService { Some(key) => key.id, None => None, }; - Ok(Some(KbMatchedLaunchSurface { + return Ok(Some(KbMatchedLaunchSurface { launch_surface_id: surface_id, matched_key_id, surface_code: "moonit".to_string(), surface_name: "Moonit".to_string(), match_kind: "token_mint_suffix".to_string(), matched_value: matched_token, - })) + })); } } @@ -555,7 +549,7 @@ fn kb_extract_payload_string( } } } - None + return None; } #[cfg(test)] @@ -584,7 +578,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fun_launch_registry(database: std::sync::Arc) { @@ -688,9 +682,7 @@ mod tests { seed_fun_launch_registry(database.clone()).await; seed_decoded_meteora_dbc_event(database.clone(), "sig-launch-origin-1").await; let service = crate::KbLaunchOriginService::new(database.clone()); - let result = service - .attribute_transaction_by_signature("sig-launch-origin-1") - .await; + let result = service.attribute_transaction_by_signature("sig-launch-origin-1").await; let results = match result { Ok(results) => results, Err(error) => panic!("launch attribution must succeed: {}", error), @@ -710,7 +702,7 @@ mod tests { assert_eq!(listed[0].match_kind, "config_account".to_string()); assert_eq!(listed[0].matched_value, "DbcDetectConfig111".to_string()); } - + async fn seed_decoded_meteora_damm_v2_event_with_moon_token( database: std::sync::Arc, signature: &str, @@ -778,9 +770,7 @@ mod tests { } } - async fn seed_bags_registry( - database: std::sync::Arc, - ) { + async fn seed_bags_registry(database: std::sync::Arc) { let service = crate::KbLaunchOriginService::new(database); let register_result = service .register_bags_pool_mapping( @@ -794,24 +784,21 @@ mod tests { panic!("bags registry must succeed: {}", error); } } - + #[tokio::test] async fn attribute_transaction_by_signature_detects_bags_from_registered_mapping() { let database = make_database().await; seed_bags_registry(database.clone()).await; seed_decoded_meteora_dbc_event(database.clone(), "sig-launch-origin-bags-1").await; let service = crate::KbLaunchOriginService::new(database.clone()); - let result = service - .attribute_transaction_by_signature("sig-launch-origin-bags-1") - .await; + let result = service.attribute_transaction_by_signature("sig-launch-origin-bags-1").await; let results = match result { Ok(results) => results, Err(error) => panic!("bags attribution must succeed: {}", error), }; assert_eq!(results.len(), 1); assert!(results[0].created_attribution); - let surface_result = - crate::get_launch_surface_by_code(database.as_ref(), "bags").await; + let surface_result = crate::get_launch_surface_by_code(database.as_ref(), "bags").await; let surface_option = match surface_result { Ok(surface_option) => surface_option, Err(error) => panic!("bags surface fetch must succeed: {}", error), @@ -844,17 +831,14 @@ mod tests { ) .await; let service = crate::KbLaunchOriginService::new(database.clone()); - let result = service - .attribute_transaction_by_signature("sig-launch-origin-moonit-1") - .await; + let result = service.attribute_transaction_by_signature("sig-launch-origin-moonit-1").await; let results = match result { Ok(results) => results, Err(error) => panic!("moonit attribution must succeed: {}", error), }; assert_eq!(results.len(), 1); assert!(results[0].created_attribution); - let surface_result = - crate::get_launch_surface_by_code(database.as_ref(), "moonit").await; + let surface_result = crate::get_launch_surface_by_code(database.as_ref(), "moonit").await; let surface_option = match surface_result { Ok(surface_option) => surface_option, Err(error) => panic!("moonit surface fetch must succeed: {}", error), diff --git a/kb_lib/src/lib.rs b/kb_lib/src/lib.rs index c442ca9..bf32302 100644 --- a/kb_lib/src/lib.rs +++ b/kb_lib/src/lib.rs @@ -20,12 +20,15 @@ mod http_client; mod http_pool; mod json_rpc_ws; mod launch_origin; +mod local_pipeline_replay; mod pair_analytic_signal; mod pair_candle_aggregation; mod pair_candle_query; +mod pair_symbol; mod pool_origin; mod solana_pubsub_ws; mod token_backfill; +mod token_metadata; mod tracing; mod trade_aggregation; mod tx_model; @@ -133,6 +136,7 @@ pub use db::get_dex_by_code; pub use db::get_dex_decoded_event_by_key; pub use db::get_known_http_endpoint; pub use db::get_known_ws_endpoint; +pub use db::get_latest_pump_fun_create_payload_by_mint; pub use db::get_launch_attribution_by_decoded_event_id; pub use db::get_launch_surface_by_code; pub use db::get_launch_surface_key_by_match; @@ -144,6 +148,7 @@ pub use db::get_pair_metric_by_pair_id; pub use db::get_pool_by_address; pub use db::get_pool_listing_by_pool_id; pub use db::get_pool_origin_by_pool_id; +pub use db::get_token_by_id; pub use db::get_token_by_mint; pub use db::get_trade_event_by_decoded_event_id; pub use db::get_wallet_by_address; @@ -154,6 +159,7 @@ pub use db::insert_chain_instruction; pub use db::insert_db_runtime_event; pub use db::insert_onchain_observation; pub use db::list_chain_instructions_by_transaction_id; +pub use db::list_chain_transaction_signatures_for_replay; pub use db::list_db_metadata; pub use db::list_dex_decoded_events_by_transaction_id; pub use db::list_dexes; @@ -181,12 +187,14 @@ pub use db::list_recent_swaps; pub use db::list_recent_token_burn_events; pub use db::list_recent_token_mint_events; pub use db::list_tokens; +pub use db::list_tokens_missing_metadata; pub use db::list_trade_events_by_pair_id; pub use db::list_trade_events_by_transaction_id; pub use db::list_wallet_holdings_by_wallet_id; pub use db::list_wallet_participations_by_pool_id; pub use db::list_wallet_participations_by_wallet_id; pub use db::list_wallets; +pub use db::update_pair_symbol; pub use db::upsert_chain_slot; pub use db::upsert_chain_transaction; pub use db::upsert_db_metadata; @@ -307,11 +315,19 @@ pub use json_rpc_ws::parse_kb_json_rpc_ws_incoming_text; pub use json_rpc_ws::parse_kb_json_rpc_ws_incoming_value; pub use launch_origin::KbLaunchAttributionResult; pub use launch_origin::KbLaunchOriginService; +pub use local_pipeline_replay::KbLocalPipelineReplayConfig; +pub use local_pipeline_replay::KbLocalPipelineReplayResult; +pub use local_pipeline_replay::KbLocalPipelineReplayService; +pub use local_pipeline_replay::kb_replay_local_pipeline; pub use pair_analytic_signal::KbPairAnalyticSignalResult; pub use pair_analytic_signal::KbPairAnalyticSignalService; pub use pair_candle_aggregation::KbPairCandleAggregationResult; pub use pair_candle_aggregation::KbPairCandleAggregationService; pub use pair_candle_query::KbPairCandleQueryService; +pub use pair_symbol::KbPairSymbolRefreshResult; +pub use pair_symbol::KbPairSymbolRefreshService; +pub use pair_symbol::kb_build_pair_symbol; +pub use pair_symbol::kb_refresh_pair_symbols; pub use pool_origin::KbPoolOriginResult; pub use pool_origin::KbPoolOriginService; pub use solana_pubsub_ws::KbSolanaWsTypedNotification; @@ -320,6 +336,8 @@ pub use solana_pubsub_ws::parse_kb_solana_ws_typed_notification_from_event; pub use token_backfill::KbPoolBackfillResult; pub use token_backfill::KbTokenBackfillResult; pub use token_backfill::KbTokenBackfillService; +pub use token_metadata::KbTokenMetadataBackfillResult; +pub use token_metadata::KbTokenMetadataBackfillService; pub use tracing::KbTracingGuard; pub use tracing::init_tracing; pub use trade_aggregation::KbTradeAggregationResult; diff --git a/kb_lib/src/local_pipeline_replay.rs b/kb_lib/src/local_pipeline_replay.rs new file mode 100644 index 0000000..a9a8fa9 --- /dev/null +++ b/kb_lib/src/local_pipeline_replay.rs @@ -0,0 +1,244 @@ +// file: kb_lib/src/local_pipeline_replay.rs + +//! Local pipeline replay from already persisted raw transaction data. +//! +//! This service does not fetch historical transactions from Solana RPC. It +//! reuses rows already present in `kb_chain_transactions` and replays the +//! deterministic local pipeline over their signatures. + +/// Configuration for a local pipeline replay pass. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct KbLocalPipelineReplayConfig { + /// Maximum number of persisted transactions to replay. + pub limit: std::option::Option, + /// Whether token metadata backfill should run after local replay. + pub refresh_missing_token_metadata: bool, + /// Maximum number of missing token metadata rows to resolve. + pub token_metadata_limit: std::option::Option, +} + +impl Default for KbLocalPipelineReplayConfig { + fn default() -> Self { + return Self { + limit: Some(10_000), + refresh_missing_token_metadata: false, + token_metadata_limit: Some(250), + }; + } +} + +/// Summary of a local pipeline replay pass. +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct KbLocalPipelineReplayResult { + /// Number of transaction signatures selected for replay. + pub selected_transaction_count: usize, + /// Number of transactions replayed without a fatal per-signature error. + pub replayed_transaction_count: usize, + /// Number of transactions that produced a decode error. + pub decode_error_count: usize, + /// Number of transactions that produced a detect error. + pub detect_error_count: usize, + /// Number of transactions that produced a trade aggregation error. + pub trade_aggregation_error_count: usize, + /// Number of transactions that produced a candle aggregation error. + pub pair_candle_error_count: usize, + /// Number of transactions that produced an analytic signal error. + pub analytic_signal_error_count: usize, + /// Total decoded events returned by replayed decode calls. + pub decoded_event_count: usize, + /// Total detection results returned by replayed detect calls. + pub detection_count: usize, + /// Total trade aggregation results returned by replayed aggregation calls. + pub trade_event_count: usize, + /// Total candle aggregation results returned by replayed candle calls. + pub pair_candle_count: usize, + /// Total analytic signal results returned by replayed analytic calls. + pub analytic_signal_count: usize, + /// Number of token metadata rows updated after replay. + pub token_metadata_updated_count: usize, + /// Number of pair symbols updated after replay. + pub pair_symbol_updated_count: usize, + /// Number of errors outside per-signature replay. + pub global_error_count: usize, +} + +/// Local pipeline replay service. +#[derive(Debug, Clone)] +pub struct KbLocalPipelineReplayService { + database: std::sync::Arc, + http_pool: std::option::Option>, + http_role: std::string::String, +} + +impl KbLocalPipelineReplayService { + /// Creates a new local-only pipeline replay service. + pub fn new(database: std::sync::Arc) -> Self { + return Self { + database, + http_pool: None, + http_role: "local_metadata".to_string(), + }; + } + + /// Creates a new pipeline replay service able to refresh token metadata over Solana HTTP RPC. + pub fn new_with_http_pool( + http_pool: std::sync::Arc, + database: std::sync::Arc, + http_role: std::string::String, + ) -> Self { + return Self { + database, + http_pool: Some(http_pool), + http_role, + }; + } + + /// Replays the local pipeline from persisted raw chain transaction rows. + pub async fn replay_local_pipeline( + &self, + config: &crate::KbLocalPipelineReplayConfig, + ) -> Result { + let signatures_result = crate::list_chain_transaction_signatures_for_replay( + self.database.as_ref(), + config.limit, + ) + .await; + let signatures = match signatures_result { + Ok(signatures) => signatures, + Err(error) => return Err(error), + }; + let dex_decode = crate::KbDexDecodeService::new(self.database.clone()); + let dex_detect = crate::KbDexDetectService::new(self.database.clone()); + let trade_aggregation = crate::KbTradeAggregationService::new(self.database.clone()); + let pair_candle_aggregation = + crate::KbPairCandleAggregationService::new(self.database.clone()); + let pair_analytic_signal = crate::KbPairAnalyticSignalService::new(self.database.clone()); + let mut result = KbLocalPipelineReplayResult { + selected_transaction_count: signatures.len(), + ..Default::default() + }; + for signature in signatures { + tracing::debug!( + signature = %signature, + "replaying local pipeline for persisted transaction" + ); + let decode_result = + dex_decode.decode_transaction_by_signature(signature.as_str()).await; + match decode_result { + Ok(decoded_events) => { + result.decoded_event_count += decoded_events.len(); + }, + Err(error) => { + result.decode_error_count += 1; + tracing::warn!( + signature = %signature, + error = %error, + "local pipeline replay decode step failed" + ); + continue; + }, + } + let detect_result = + dex_detect.detect_transaction_by_signature(signature.as_str()).await; + match detect_result { + Ok(detections) => { + result.detection_count += detections.len(); + }, + Err(error) => { + result.detect_error_count += 1; + tracing::warn!( + signature = %signature, + error = %error, + "local pipeline replay detect step failed" + ); + continue; + }, + } + let trade_result = + trade_aggregation.record_transaction_by_signature(signature.as_str()).await; + match trade_result { + Ok(trade_results) => { + result.trade_event_count += trade_results.len(); + }, + Err(error) => { + result.trade_aggregation_error_count += 1; + tracing::warn!( + signature = %signature, + error = %error, + "local pipeline replay trade aggregation step failed" + ); + continue; + }, + } + let candle_result = pair_candle_aggregation + .record_transaction_by_signature(signature.as_str()) + .await; + match candle_result { + Ok(candle_results) => { + result.pair_candle_count += candle_results.len(); + }, + Err(error) => { + result.pair_candle_error_count += 1; + tracing::warn!( + signature = %signature, + error = %error, + "local pipeline replay candle aggregation step failed" + ); + }, + } + let analytic_result = + pair_analytic_signal.record_transaction_by_signature(signature.as_str()).await; + match analytic_result { + Ok(analytic_results) => { + result.analytic_signal_count += analytic_results.len(); + }, + Err(error) => { + result.analytic_signal_error_count += 1; + tracing::warn!( + signature = %signature, + error = %error, + "local pipeline replay analytic signal step failed" + ); + }, + } + result.replayed_transaction_count += 1; + } + if config.refresh_missing_token_metadata { + let metadata_service = match &self.http_pool { + Some(http_pool) => crate::KbTokenMetadataBackfillService::new( + http_pool.clone(), + self.database.clone(), + self.http_role.clone(), + ), + None => crate::KbTokenMetadataBackfillService::new_local(self.database.clone()), + }; + let metadata_result = metadata_service + .backfill_missing_token_metadata(config.token_metadata_limit) + .await; + match metadata_result { + Ok(metadata_result) => { + result.token_metadata_updated_count += metadata_result.updated_token_count; + }, + Err(error) => { + result.global_error_count += 1; + tracing::warn!( + error = %error, + "token metadata refresh failed after local pipeline replay" + ); + }, + } + } + return Ok(result); + } +} + +/// Replays the local pipeline from persisted raw chain transaction rows. +pub async fn kb_replay_local_pipeline( + database: std::sync::Arc, + config: &crate::KbLocalPipelineReplayConfig, +) -> Result { + let service = crate::KbLocalPipelineReplayService::new(database); + return service.replay_local_pipeline(config).await; +} diff --git a/kb_lib/src/pair_analytic_signal.rs b/kb_lib/src/pair_analytic_signal.rs index 5715384..8463142 100644 --- a/kb_lib/src/pair_analytic_signal.rs +++ b/kb_lib/src/pair_analytic_signal.rs @@ -28,10 +28,7 @@ impl KbPairAnalyticSignalService { /// Creates a new pair analytic signal service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Records richer analytic signals for one resolved transaction signature. @@ -52,7 +49,7 @@ impl KbPairAnalyticSignalService { "cannot record pair analytic signals for unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { Some(transaction_id) => transaction_id, @@ -61,7 +58,7 @@ impl KbPairAnalyticSignalService { "transaction '{}' has no internal id", signature ))); - } + }, }; let trade_events_result = crate::list_trade_events_by_transaction_id(self.database.as_ref(), transaction_id) @@ -87,9 +84,7 @@ impl KbPairAnalyticSignalService { Ok(bucket_start_unix) => bucket_start_unix, Err(error) => return Err(error), }; - let entry = impacted_pairs - .entry(trade_event.pair_id) - .or_insert_with(std::collections::BTreeSet::::new); + let entry = impacted_pairs.entry(trade_event.pair_id).or_default(); entry.insert(bucket_start_unix); } let mut results = std::vec::Vec::new(); @@ -269,7 +264,7 @@ impl KbPairAnalyticSignalService { return Err(error); } } - Ok(results) + return Ok(results); } async fn trade_event_unix_time( @@ -290,8 +285,8 @@ impl KbPairAnalyticSignalService { None => return Ok(Some(trade_event.created_at.timestamp())), }; match transaction.block_time_unix { - Some(block_time_unix) => Ok(Some(block_time_unix)), - None => Ok(Some(trade_event.created_at.timestamp())), + Some(block_time_unix) => return Ok(Some(block_time_unix)), + None => return Ok(Some(trade_event.created_at.timestamp())), } } @@ -333,24 +328,25 @@ impl KbPairAnalyticSignalService { first_transaction_id, transaction_id, ); - crate::upsert_pair_analytic_signal(self.database.as_ref(), &dto).await + return crate::upsert_pair_analytic_signal(self.database.as_ref(), &dto).await; } async fn persist_signal( &self, signal: KbPendingPairAnalyticSignal, ) -> Result { - self.upsert_signal( - signal.pair_id, - signal.signal_kind, - signal.severity, - signal.timeframe_seconds, - signal.bucket_start_unix, - signal.score, - signal.signal_value, - signal.transaction_id, - ) - .await + return self + .upsert_signal( + signal.pair_id, + signal.signal_kind, + signal.severity, + signal.timeframe_seconds, + signal.bucket_start_unix, + signal.score, + signal.signal_value, + signal.transaction_id, + ) + .await; } } @@ -376,7 +372,7 @@ fn kb_bucket_start_unix( timeframe_seconds ))); } - Ok((event_time_unix / timeframe_seconds) * timeframe_seconds) + return Ok((event_time_unix / timeframe_seconds) * timeframe_seconds); } fn kb_maybe_build_trade_burst_signal( @@ -392,7 +388,7 @@ fn kb_maybe_build_trade_burst_signal( } else { crate::KbAnalysisSignalSeverity::Medium }; - Some(KbPendingPairAnalyticSignal { + return Some(KbPendingPairAnalyticSignal { pair_id, signal_kind: "trade_burst_60s".to_string(), severity, @@ -407,7 +403,7 @@ fn kb_maybe_build_trade_burst_signal( "bucketStartUnix": candle.bucket_start_unix }), transaction_id: Some(transaction_id), - }) + }); } fn kb_maybe_build_buy_sell_imbalance_signal( @@ -428,7 +424,7 @@ fn kb_maybe_build_buy_sell_imbalance_signal( } else { crate::KbAnalysisSignalSeverity::Medium }; - Some(KbPendingPairAnalyticSignal { + return Some(KbPendingPairAnalyticSignal { pair_id, signal_kind: "buy_sell_imbalance_60s".to_string(), severity, @@ -444,7 +440,7 @@ fn kb_maybe_build_buy_sell_imbalance_signal( "bucketStartUnix": candle.bucket_start_unix }), transaction_id: Some(transaction_id), - }) + }); } fn kb_maybe_build_price_jump_signal( @@ -504,7 +500,7 @@ fn kb_maybe_build_price_jump_signal( transaction_id: Some(transaction_id), }); } - None + return None; } fn kb_maybe_build_volume_spike_signal( @@ -543,7 +539,7 @@ fn kb_maybe_build_volume_spike_signal( } else { crate::KbAnalysisSignalSeverity::Medium }; - Some(KbPendingPairAnalyticSignal { + return Some(KbPendingPairAnalyticSignal { pair_id, signal_kind: "volume_spike_60s".to_string(), severity, @@ -558,7 +554,7 @@ fn kb_maybe_build_volume_spike_signal( "bucketStartUnix": candle.bucket_start_unix }), transaction_id: Some(transaction_id), - }) + }); } #[cfg(test)] @@ -587,7 +583,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fluxbeam_swap_transaction( @@ -661,15 +657,12 @@ mod tests { if let Err(error) = detect_result { panic!("dex detect must succeed: {}", error); } - let trade_result = trade_aggregation - .record_transaction_by_signature(signature) - .await; + let trade_result = trade_aggregation.record_transaction_by_signature(signature).await; if let Err(error) = trade_result { panic!("trade aggregation must succeed: {}", error); } - let candle_result = pair_candle_aggregation - .record_transaction_by_signature(signature) - .await; + let candle_result = + pair_candle_aggregation.record_transaction_by_signature(signature).await; if let Err(error) = candle_result { panic!("pair candle aggregation must succeed: {}", error); } @@ -687,9 +680,8 @@ mod tests { ) .await; let service = crate::KbPairAnalyticSignalService::new(database.clone()); - let record_result = service - .record_transaction_by_signature("sig-analytic-first-trade") - .await; + let record_result = + service.record_transaction_by_signature("sig-analytic-first-trade").await; let results = match record_result { Ok(results) => results, Err(error) => panic!("analytic signal service must succeed: {}", error), @@ -766,47 +758,32 @@ mod tests { ) .await; let service = crate::KbPairAnalyticSignalService::new(database.clone()); - let record_1 = service - .record_transaction_by_signature("sig-analytic-bucket-1") - .await; + let record_1 = service.record_transaction_by_signature("sig-analytic-bucket-1").await; if let Err(error) = record_1 { panic!("analytic signal service call 1 must succeed: {}", error); } - let record_2 = service - .record_transaction_by_signature("sig-analytic-bucket-2") - .await; + let record_2 = service.record_transaction_by_signature("sig-analytic-bucket-2").await; if let Err(error) = record_2 { panic!("analytic signal service call 2 must succeed: {}", error); } - let record_3 = service - .record_transaction_by_signature("sig-analytic-bucket-3") - .await; + let record_3 = service.record_transaction_by_signature("sig-analytic-bucket-3").await; if let Err(error) = record_3 { panic!("analytic signal service call 3 must succeed: {}", error); } - let record_4 = service - .record_transaction_by_signature("sig-analytic-bucket-4") - .await; + let record_4 = service.record_transaction_by_signature("sig-analytic-bucket-4").await; if let Err(error) = record_4 { panic!("analytic signal service call 4 must succeed: {}", error); } - let record_5 = service - .record_transaction_by_signature("sig-analytic-bucket-5") - .await; + let record_5 = service.record_transaction_by_signature("sig-analytic-bucket-5").await; let results = match record_5 { Ok(results) => results, Err(error) => panic!("analytic signal service call 5 must succeed: {}", error), }; assert!(!results.is_empty()); - let second_result = service - .record_transaction_by_signature("sig-analytic-bucket-5") - .await; + let second_result = service.record_transaction_by_signature("sig-analytic-bucket-5").await; let second_results = match second_result { Ok(second_results) => second_results, - Err(error) => panic!( - "second analytic signal service call must succeed: {}", - error - ), + Err(error) => panic!("second analytic signal service call must succeed: {}", error), }; assert!(!second_results.is_empty()); let pools_result = crate::list_pools(database.as_ref()).await; @@ -855,10 +832,7 @@ mod tests { Some(trade_burst) => trade_burst, None => panic!("trade burst signal must exist"), }; - assert_eq!( - trade_burst.severity, - crate::KbAnalysisSignalSeverity::Medium - ); + assert_eq!(trade_burst.severity, crate::KbAnalysisSignalSeverity::Medium); let jump_result = crate::get_pair_analytic_signal_by_key( database.as_ref(), pair_id, diff --git a/kb_lib/src/pair_candle_aggregation.rs b/kb_lib/src/pair_candle_aggregation.rs index e4c1688..e65d30a 100644 --- a/kb_lib/src/pair_candle_aggregation.rs +++ b/kb_lib/src/pair_candle_aggregation.rs @@ -29,15 +29,12 @@ impl KbPairCandleAggregationService { /// Creates a new pair-candle aggregation service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Returns the list of materialized timeframes in seconds. pub fn materialized_timeframes_seconds(&self) -> std::vec::Vec { - vec![60, 300, 900, 3600] + return vec![60, 300, 900, 3600]; } /// Rebuilds all impacted materialized candles for one resolved transaction signature. @@ -58,7 +55,7 @@ impl KbPairCandleAggregationService { "cannot aggregate pair candles for unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { Some(transaction_id) => transaction_id, @@ -67,7 +64,7 @@ impl KbPairCandleAggregationService { "transaction '{}' has no internal id", signature ))); - } + }, }; let trade_events_result = crate::list_trade_events_by_transaction_id(self.database.as_ref(), transaction_id) @@ -149,7 +146,7 @@ impl KbPairCandleAggregationService { return Err(error); } } - Ok(results) + return Ok(results); } async fn rebuild_one_candle( @@ -186,12 +183,12 @@ impl KbPairCandleAggregationService { Ok(pair_candle_id) => pair_candle_id, Err(error) => return Err(error), }; - Ok(Some(crate::KbPairCandleAggregationResult { + return Ok(Some(crate::KbPairCandleAggregationResult { pair_id, timeframe_seconds, bucket_start_unix, pair_candle_id, - })) + })); } } @@ -243,7 +240,7 @@ pub(crate) async fn kb_build_candle_from_trade_events( if time_compare != std::cmp::Ordering::Equal { return time_compare; } - left.decoded_event_id.cmp(&right.decoded_event_id) + return left.decoded_event_id.cmp(&right.decoded_event_id); }); let open_price_quote_per_base = rows[0].price_quote_per_base; let close_price_quote_per_base = rows[rows.len() - 1].price_quote_per_base; @@ -271,7 +268,7 @@ pub(crate) async fn kb_build_candle_from_trade_events( base_volume_raw = kb_add_raw_amounts(base_volume_raw, row.base_amount_raw.clone()); quote_volume_raw = kb_add_raw_amounts(quote_volume_raw, row.quote_amount_raw.clone()); } - Ok(Some(crate::KbPairCandleDto::new( + return Ok(Some(crate::KbPairCandleDto::new( pair_id, timeframe_seconds, bucket_start_unix, @@ -287,7 +284,7 @@ pub(crate) async fn kb_build_candle_from_trade_events( quote_volume_raw, Some(rows[0].signature.clone()), Some(rows[rows.len() - 1].signature.clone()), - ))) + ))); } pub(crate) async fn kb_extract_trade_event_unix_time( @@ -305,8 +302,8 @@ pub(crate) async fn kb_extract_trade_event_unix_time( None => return Ok(Some(trade_event.created_at.timestamp())), }; match transaction.block_time_unix { - Some(block_time_unix) => Ok(Some(block_time_unix)), - None => Ok(Some(trade_event.created_at.timestamp())), + Some(block_time_unix) => return Ok(Some(block_time_unix)), + None => return Ok(Some(trade_event.created_at.timestamp())), } } @@ -320,8 +317,7 @@ pub(crate) fn kb_bucket_start_unix( timeframe_seconds ))); } - - Ok((event_time_unix / timeframe_seconds) * timeframe_seconds) + return Ok((event_time_unix / timeframe_seconds) * timeframe_seconds); } fn kb_add_raw_amounts( @@ -329,9 +325,9 @@ fn kb_add_raw_amounts( right: std::option::Option, ) -> std::option::Option { match (left, right) { - (None, None) => None, - (Some(left), None) => Some(left), - (None, Some(right)) => Some(right), + (None, None) => return None, + (Some(left), None) => return Some(left), + (None, Some(right)) => return Some(right), (Some(left), Some(right)) => { let left_value_result = left.parse::(); let left_value = match left_value_result { @@ -343,8 +339,8 @@ fn kb_add_raw_amounts( Ok(right_value) => right_value, Err(_) => return Some(left), }; - Some((left_value + right_value).to_string()) - } + return Some((left_value + right_value).to_string()); + }, } } @@ -385,7 +381,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fluxbeam_swap_transaction( @@ -457,9 +453,7 @@ mod tests { if let Err(error) = detect_result { panic!("dex detect must succeed: {}", error); } - let trade_result = trade_aggregation - .record_transaction_by_signature(signature) - .await; + let trade_result = trade_aggregation.record_transaction_by_signature(signature).await; if let Err(error) = trade_result { panic!("trade aggregation must succeed: {}", error); } @@ -493,21 +487,15 @@ mod tests { ) .await; let service = crate::KbPairCandleAggregationService::new(database.clone()); - let result_1 = service - .record_transaction_by_signature("sig-pair-candle-1") - .await; + let result_1 = service.record_transaction_by_signature("sig-pair-candle-1").await; if let Err(error) = result_1 { panic!("candle aggregation 1 must succeed: {}", error); } - let result_2 = service - .record_transaction_by_signature("sig-pair-candle-2") - .await; + let result_2 = service.record_transaction_by_signature("sig-pair-candle-2").await; if let Err(error) = result_2 { panic!("candle aggregation 2 must succeed: {}", error); } - let result_3 = service - .record_transaction_by_signature("sig-pair-candle-3") - .await; + let result_3 = service.record_transaction_by_signature("sig-pair-candle-3").await; if let Err(error) = result_3 { panic!("candle aggregation 3 must succeed: {}", error); } @@ -558,17 +546,15 @@ mod tests { ) .await; let service = crate::KbPairCandleAggregationService::new(database.clone()); - let first_result = service - .record_transaction_by_signature("sig-pair-candle-idempotent") - .await; + let first_result = + service.record_transaction_by_signature("sig-pair-candle-idempotent").await; let first_results = match first_result { Ok(first_results) => first_results, Err(error) => panic!("first candle aggregation must succeed: {}", error), }; assert!(!first_results.is_empty()); - let second_result = service - .record_transaction_by_signature("sig-pair-candle-idempotent") - .await; + let second_result = + service.record_transaction_by_signature("sig-pair-candle-idempotent").await; let second_results = match second_result { Ok(second_results) => second_results, Err(error) => panic!("second candle aggregation must succeed: {}", error), diff --git a/kb_lib/src/pair_candle_query.rs b/kb_lib/src/pair_candle_query.rs index ae183a2..a883238 100644 --- a/kb_lib/src/pair_candle_query.rs +++ b/kb_lib/src/pair_candle_query.rs @@ -14,7 +14,7 @@ pub struct KbPairCandleQueryService { impl KbPairCandleQueryService { /// Creates a new pair-candle query service. pub fn new(database: std::sync::Arc) -> Self { - Self { database } + return Self { database }; } /// Lists candles for one pair and one timeframe. @@ -113,15 +113,15 @@ impl KbPairCandleQueryService { candles.push(candle); } } - Ok(candles) + return Ok(candles); } } fn kb_is_materialized_timeframe(timeframe_seconds: i64) -> bool { - timeframe_seconds == 60 + return timeframe_seconds == 60 || timeframe_seconds == 300 || timeframe_seconds == 900 - || timeframe_seconds == 3600 + || timeframe_seconds == 3600; } fn kb_filter_candles_by_bucket_range( @@ -143,7 +143,7 @@ fn kb_filter_candles_by_bucket_range( } filtered.push(candle); } - filtered + return filtered; } #[cfg(test)] @@ -172,7 +172,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fluxbeam_swap_transaction( @@ -244,9 +244,7 @@ mod tests { if let Err(error) = detect_result { panic!("dex detect must succeed: {}", error); } - let trade_result = trade_aggregation - .record_transaction_by_signature(signature) - .await; + let trade_result = trade_aggregation.record_transaction_by_signature(signature).await; if let Err(error) = trade_result { panic!("trade aggregation must succeed: {}", error); } @@ -280,21 +278,18 @@ mod tests { ) .await; let trade_service = crate::KbPairCandleAggregationService::new(database.clone()); - let record_1 = trade_service - .record_transaction_by_signature("sig-pair-candle-query-1") - .await; + let record_1 = + trade_service.record_transaction_by_signature("sig-pair-candle-query-1").await; if let Err(error) = record_1 { panic!("candle aggregation 1 must succeed: {}", error); } - let record_2 = trade_service - .record_transaction_by_signature("sig-pair-candle-query-2") - .await; + let record_2 = + trade_service.record_transaction_by_signature("sig-pair-candle-query-2").await; if let Err(error) = record_2 { panic!("candle aggregation 2 must succeed: {}", error); } - let record_3 = trade_service - .record_transaction_by_signature("sig-pair-candle-query-3") - .await; + let record_3 = + trade_service.record_transaction_by_signature("sig-pair-candle-query-3").await; if let Err(error) = record_3 { panic!("candle aggregation 3 must succeed: {}", error); } @@ -315,9 +310,7 @@ mod tests { }; let pair_id = pair.id.unwrap_or_default(); let query_service = crate::KbPairCandleQueryService::new(database); - let candles_result = query_service - .list_pair_candles(pair_id, 120, None, None, false) - .await; + let candles_result = query_service.list_pair_candles(pair_id, 120, None, None, false).await; let candles = match candles_result { Ok(candles) => candles, Err(error) => panic!("custom candle query must succeed: {}", error), @@ -375,9 +368,7 @@ mod tests { }; assert_eq!(materialized.len(), 0); let query_service = crate::KbPairCandleQueryService::new(database); - let candles_result = query_service - .list_pair_candles(pair_id, 60, None, None, true) - .await; + let candles_result = query_service.list_pair_candles(pair_id, 60, None, None, true).await; let candles = match candles_result { Ok(candles) => candles, Err(error) => panic!("fallback candle query must succeed: {}", error), diff --git a/kb_lib/src/pair_symbol.rs b/kb_lib/src/pair_symbol.rs new file mode 100644 index 0000000..785aae4 --- /dev/null +++ b/kb_lib/src/pair_symbol.rs @@ -0,0 +1,294 @@ +// file: kb_lib/src/pair_symbol.rs + +//! Pair display-symbol derivation. +//! +//! This module derives stable pair labels from the token rows already persisted +//! in `kb_tokens`. It deliberately keeps SQL access in `db/queries` and only +//! orchestrates DTO reads and updates. + +/// Summary produced by a pair-symbol refresh pass. +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct KbPairSymbolRefreshResult { + /// Number of pairs considered by this pass. + pub total_pair_count: usize, + /// Number of pair rows updated. + pub updated_pair_count: usize, + /// Number of pair rows already correct. + pub skipped_pair_count: usize, + /// Number of pairs skipped because a related token row was missing. + pub missing_token_count: usize, +} + +/// Service that refreshes `kb_pairs.symbol` from base and quote token metadata. +#[derive(Debug, Clone)] +pub struct KbPairSymbolRefreshService { + database: std::sync::Arc, +} + +impl KbPairSymbolRefreshService { + /// Creates a new pair-symbol refresh service. + pub fn new(database: std::sync::Arc) -> Self { + return Self { database }; + } + + /// Refreshes all persisted pair display symbols. + pub async fn refresh_pair_symbols( + &self, + ) -> Result { + return kb_refresh_pair_symbols(self.database.as_ref()).await; + } +} + +/// Refreshes all persisted pair display symbols. +pub async fn kb_refresh_pair_symbols( + database: &crate::KbDatabase, +) -> Result { + let pairs_result = crate::list_pairs(database).await; + let pairs = match pairs_result { + Ok(pairs) => pairs, + Err(error) => return Err(error), + }; + let mut result = KbPairSymbolRefreshResult { + total_pair_count: pairs.len(), + ..Default::default() + }; + for pair in pairs { + let pair_id = match pair.id { + Some(pair_id) => pair_id, + None => { + return Err(crate::KbError::InvalidState( + "pair row has no internal id".to_string(), + )); + }, + }; + let base_token_result = crate::get_token_by_id(database, pair.base_token_id).await; + let base_token_option = match base_token_result { + Ok(base_token_option) => base_token_option, + Err(error) => return Err(error), + }; + let base_token = match base_token_option { + Some(base_token) => base_token, + None => { + result.missing_token_count += 1; + tracing::warn!( + pair_id = pair_id, + base_token_id = pair.base_token_id, + "cannot refresh pair symbol because base token is missing" + ); + continue; + }, + }; + let quote_token_result = crate::get_token_by_id(database, pair.quote_token_id).await; + let quote_token_option = match quote_token_result { + Ok(quote_token_option) => quote_token_option, + Err(error) => return Err(error), + }; + let quote_token = match quote_token_option { + Some(quote_token) => quote_token, + None => { + result.missing_token_count += 1; + tracing::warn!( + pair_id = pair_id, + quote_token_id = pair.quote_token_id, + "cannot refresh pair symbol because quote token is missing" + ); + continue; + }, + }; + let next_symbol = kb_build_pair_symbol( + base_token.symbol.as_deref(), + base_token.mint.as_str(), + quote_token.symbol.as_deref(), + quote_token.mint.as_str(), + ); + let current_symbol = kb_normalize_optional_symbol(pair.symbol.as_deref()); + if current_symbol.as_deref() == Some(next_symbol.as_str()) { + result.skipped_pair_count += 1; + continue; + } + let update_result = + crate::update_pair_symbol(database, pair_id, Some(next_symbol.as_str())).await; + match update_result { + Ok(updated) => { + if updated { + result.updated_pair_count += 1; + } else { + result.skipped_pair_count += 1; + } + }, + Err(error) => return Err(error), + } + } + return Ok(result); +} + +/// Builds a readable pair symbol from token symbols with mint fallback. +pub fn kb_build_pair_symbol( + base_symbol: std::option::Option<&str>, + base_mint: &str, + quote_symbol: std::option::Option<&str>, + quote_mint: &str, +) -> std::string::String { + let base_label = kb_pick_token_label(base_symbol, base_mint); + let quote_label = kb_pick_token_label(quote_symbol, quote_mint); + return format!("{}/{}", base_label, quote_label); +} + +fn kb_pick_token_label(symbol: std::option::Option<&str>, mint: &str) -> std::string::String { + let symbol_option = kb_normalize_optional_symbol(symbol); + match symbol_option { + Some(symbol) => return symbol, + None => return mint.trim().to_string(), + } +} + +fn kb_normalize_optional_symbol( + symbol: std::option::Option<&str>, +) -> std::option::Option { + let symbol = match symbol { + Some(symbol) => symbol.trim(), + None => return None, + }; + if symbol.is_empty() { + return None; + } + return Some(symbol.to_string()); +} + +#[cfg(test)] +mod tests { + async fn make_database() -> std::sync::Arc { + let tempdir_result = tempfile::tempdir(); + let tempdir = match tempdir_result { + Ok(tempdir) => tempdir, + Err(error) => panic!("tempdir must succeed: {}", error), + }; + let database_path = tempdir.path().join("pair_symbol.sqlite3"); + let config = crate::KbDatabaseConfig { + enabled: true, + backend: crate::KbDatabaseBackend::Sqlite, + sqlite: crate::KbSqliteDatabaseConfig { + path: database_path.to_string_lossy().to_string(), + create_if_missing: true, + busy_timeout_ms: 5000, + max_connections: 1, + auto_initialize_schema: true, + use_wal: true, + }, + }; + let database_result = crate::KbDatabase::connect_and_initialize(&config).await; + let database = match database_result { + Ok(database) => database, + Err(error) => panic!("database init must succeed: {}", error), + }; + return std::sync::Arc::new(database); + } + + #[test] + fn build_pair_symbol_uses_symbol_when_available() { + let wsol_mint = crate::WSOL_MINT_ID.to_string(); + let symbol = crate::kb_build_pair_symbol( + Some(" BASE "), + "BaseMint111", + Some("WSOL"), + wsol_mint.as_str(), + ); + assert_eq!(symbol, "BASE/WSOL"); + } + + #[test] + fn build_pair_symbol_falls_back_to_mint_when_symbol_is_missing() { + let wsol_mint = crate::WSOL_MINT_ID.to_string(); + let symbol = + crate::kb_build_pair_symbol(None, "BaseMint111", Some("WSOL"), wsol_mint.as_str()); + assert_eq!(symbol, "BaseMint111/WSOL"); + } + + #[tokio::test] + async fn refresh_pair_symbols_updates_empty_symbol() { + let database = make_database().await; + let dex_id_result = crate::upsert_dex( + database.as_ref(), + &crate::KbDexDto::new("test_dex".to_string(), "Test DEX".to_string(), None, None, true), + ) + .await; + let dex_id = match dex_id_result { + Ok(dex_id) => dex_id, + Err(error) => panic!("dex upsert must succeed: {}", error), + }; + let base_token_id_result = crate::upsert_token( + database.as_ref(), + &crate::KbTokenDto::new( + "BaseMint111".to_string(), + Some("BASE".to_string()), + Some("Base Token".to_string()), + Some(6), + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + false, + ), + ) + .await; + let base_token_id = match base_token_id_result { + Ok(base_token_id) => base_token_id, + Err(error) => panic!("base token upsert must succeed: {}", error), + }; + let quote_token_id_result = crate::upsert_token( + database.as_ref(), + &crate::KbTokenDto::new( + crate::WSOL_MINT_ID.to_string(), + Some("WSOL".to_string()), + Some("Wrapped SOL".to_string()), + Some(9), + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + true, + ), + ) + .await; + let quote_token_id = match quote_token_id_result { + Ok(quote_token_id) => quote_token_id, + Err(error) => panic!("quote token upsert must succeed: {}", error), + }; + let pool_id_result = crate::upsert_pool( + database.as_ref(), + &crate::KbPoolDto::new( + dex_id, + "Pool111".to_string(), + crate::KbPoolKind::Amm, + crate::KbPoolStatus::Active, + ), + ) + .await; + let pool_id = match pool_id_result { + Ok(pool_id) => pool_id, + Err(error) => panic!("pool upsert must succeed: {}", error), + }; + let pair_id_result = crate::upsert_pair( + database.as_ref(), + &crate::KbPairDto::new(dex_id, pool_id, base_token_id, quote_token_id, None), + ) + .await; + let pair_id = match pair_id_result { + Ok(pair_id) => pair_id, + Err(error) => panic!("pair upsert must succeed: {}", error), + }; + let result = crate::kb_refresh_pair_symbols(database.as_ref()).await; + let result = match result { + Ok(result) => result, + Err(error) => panic!("pair symbol refresh must succeed: {}", error), + }; + assert_eq!(result.total_pair_count, 1); + assert_eq!(result.updated_pair_count, 1); + let pair_result = crate::get_pair_by_pool_id(database.as_ref(), pool_id).await; + let pair_option = match pair_result { + Ok(pair_option) => pair_option, + Err(error) => panic!("pair fetch must succeed: {}", error), + }; + let pair = match pair_option { + Some(pair) => pair, + None => panic!("pair must exist"), + }; + assert_eq!(pair.id, Some(pair_id)); + assert_eq!(pair.symbol.as_deref(), Some("BASE/WSOL")); + } +} diff --git a/kb_lib/src/pool_origin.rs b/kb_lib/src/pool_origin.rs index c4a0d64..05167c0 100644 --- a/kb_lib/src/pool_origin.rs +++ b/kb_lib/src/pool_origin.rs @@ -28,10 +28,7 @@ impl KbPoolOriginService { /// Creates a new pool-origin service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Records pool-origin rows for one resolved transaction signature. @@ -52,7 +49,7 @@ impl KbPoolOriginService { "cannot record pool origins for unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { @@ -62,7 +59,7 @@ impl KbPoolOriginService { "transaction '{}' has no internal id", signature ))); - } + }, }; let decoded_events_result = crate::list_dex_decoded_events_by_transaction_id( @@ -85,7 +82,7 @@ impl KbPoolOriginService { return Err(crate::KbError::InvalidState( "decoded event has no internal id".to_string(), )); - } + }, }; let pool_address = match decoded_event.pool_account.clone() { @@ -111,7 +108,7 @@ impl KbPoolOriginService { "pool '{}' has no internal id", pool.address ))); - } + }, }; if seen_pool_ids.contains(&pool_id) { @@ -234,8 +231,7 @@ impl KbPoolOriginService { created_origin, }); } - - Ok(results) + return Ok(results); } } @@ -265,7 +261,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_bags_backed_meteora_dbc_transaction( @@ -362,9 +358,7 @@ mod tests { seed_bags_backed_meteora_dbc_transaction(database.clone(), "sig-pool-origin-1").await; let service = crate::KbPoolOriginService::new(database.clone()); - let record_result = service - .record_transaction_by_signature("sig-pool-origin-1") - .await; + let record_result = service.record_transaction_by_signature("sig-pool-origin-1").await; let results = match record_result { Ok(results) => results, Err(error) => panic!("pool-origin recording must succeed: {}", error), @@ -398,9 +392,7 @@ mod tests { let service = crate::KbPoolOriginService::new(database.clone()); - let first_result = service - .record_transaction_by_signature("sig-pool-origin-2") - .await; + let first_result = service.record_transaction_by_signature("sig-pool-origin-2").await; let first_results = match first_result { Ok(first_results) => first_results, Err(error) => panic!("first pool-origin recording must succeed: {}", error), @@ -408,9 +400,7 @@ mod tests { assert_eq!(first_results.len(), 1); assert!(first_results[0].created_origin); - let second_result = service - .record_transaction_by_signature("sig-pool-origin-2") - .await; + let second_result = service.record_transaction_by_signature("sig-pool-origin-2").await; let second_results = match second_result { Ok(second_results) => second_results, Err(error) => panic!("second pool-origin recording must succeed: {}", error), diff --git a/kb_lib/src/solana_pubsub_ws.rs b/kb_lib/src/solana_pubsub_ws.rs index 31bcdbd..9b1842b 100644 --- a/kb_lib/src/solana_pubsub_ws.rs +++ b/kb_lib/src/solana_pubsub_ws.rs @@ -73,9 +73,9 @@ pub fn parse_kb_solana_ws_typed_notification( >(notification.params.result.clone()); return match parse_result { Ok(value) => Ok(KbSolanaWsTypedNotification::Logs(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse logsNotification payload: {error}" - ))), + Err(error) => { + Err(crate::KbError::Json(format!("cannot parse logsNotification payload: {error}"))) + }, }; } if notification.method == "programNotification" { @@ -119,9 +119,9 @@ pub fn parse_kb_solana_ws_typed_notification( ); return match parse_result { Ok(value) => Ok(KbSolanaWsTypedNotification::Slot(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse slotNotification payload: {error}" - ))), + Err(error) => { + Err(crate::KbError::Json(format!("cannot parse slotNotification payload: {error}"))) + }, }; } if notification.method == "slotsUpdatesNotification" { @@ -141,15 +141,15 @@ pub fn parse_kb_solana_ws_typed_notification( ); return match parse_result { Ok(value) => Ok(KbSolanaWsTypedNotification::Vote(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot parse voteNotification payload: {error}" - ))), + Err(error) => { + Err(crate::KbError::Json(format!("cannot parse voteNotification payload: {error}"))) + }, }; } - Err(crate::KbError::Json(format!( + return Err(crate::KbError::Json(format!( "unsupported Solana websocket notification method '{}'", notification.method - ))) + ))); } /// Parses a typed Solana PubSub notification from a generic websocket event. @@ -165,29 +165,29 @@ pub fn parse_kb_solana_ws_typed_notification_from_event( crate::WsEvent::SubscriptionNotification { notification, .. } => { let parse_result = parse_kb_solana_ws_typed_notification(notification); match parse_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(error), + Ok(value) => return Ok(Some(value)), + Err(error) => return Err(error), } - } + }, crate::WsEvent::JsonRpcNotificationWithoutSubscription { notification, .. } => { let parse_result = parse_kb_solana_ws_typed_notification(notification); match parse_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(error), + Ok(value) => return Ok(Some(value)), + Err(error) => return Err(error), } - } + }, crate::WsEvent::JsonRpcMessage { message, .. } => match message { crate::KbJsonRpcWsIncomingMessage::Notification(notification) => { let parse_result = parse_kb_solana_ws_typed_notification(notification); match parse_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(error), + Ok(value) => return Ok(Some(value)), + Err(error) => return Err(error), } - } - crate::KbJsonRpcWsIncomingMessage::SuccessResponse(_) => Ok(None), - crate::KbJsonRpcWsIncomingMessage::ErrorResponse(_) => Ok(None), + }, + crate::KbJsonRpcWsIncomingMessage::SuccessResponse(_) => return Ok(None), + crate::KbJsonRpcWsIncomingMessage::ErrorResponse(_) => return Ok(None), }, - _ => Ok(None), + _ => return Ok(None), } } @@ -204,7 +204,7 @@ impl crate::WsClient { Ok(config_value) => config_value, Err(error) => return Err(error), }; - self.account_subscribe_raw(pubkey, config_value).await + return self.account_subscribe_raw(pubkey, config_value).await; } /// Typed helper for `blockSubscribe`. @@ -224,7 +224,7 @@ impl crate::WsClient { Ok(config_value) => config_value, Err(error) => return Err(error), }; - self.block_subscribe_raw(filter_value, config_value).await + return self.block_subscribe_raw(filter_value, config_value).await; } /// Typed helper for `logsSubscribe`. @@ -244,7 +244,7 @@ impl crate::WsClient { Ok(config_value) => config_value, Err(error) => return Err(error), }; - self.logs_subscribe_raw(filter_value, config_value).await + return self.logs_subscribe_raw(filter_value, config_value).await; } /// Typed helper for `programSubscribe`. @@ -259,7 +259,7 @@ impl crate::WsClient { Ok(config_value) => config_value, Err(error) => return Err(error), }; - self.program_subscribe_raw(program_id, config_value).await + return self.program_subscribe_raw(program_id, config_value).await; } /// Typed helper for `signatureSubscribe`. @@ -274,7 +274,7 @@ impl crate::WsClient { Ok(config_value) => config_value, Err(error) => return Err(error), }; - self.signature_subscribe_raw(signature, config_value).await + return self.signature_subscribe_raw(signature, config_value).await; } } @@ -287,11 +287,10 @@ where { let value_result = serde_json::to_value(value); match value_result { - Ok(value) => Ok(value), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize {}: {error}", - label - ))), + Ok(value) => return Ok(value), + Err(error) => { + return Err(crate::KbError::Json(format!("cannot serialize {}: {error}", label))); + }, } } @@ -306,14 +305,16 @@ where Some(value) => { let value_result = serde_json::to_value(value); match value_result { - Ok(value) => Ok(Some(value)), - Err(error) => Err(crate::KbError::Json(format!( - "cannot serialize {}: {error}", - label - ))), + Ok(value) => return Ok(Some(value)), + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot serialize {}: {error}", + label + ))); + }, } - } - None => Ok(None), + }, + None => return Ok(None), } } @@ -335,7 +336,7 @@ mod tests { event_channel_capacity: 32, auto_reconnect: false, }; - crate::WsClient::new(endpoint).expect("client creation must succeed") + return crate::WsClient::new(endpoint).expect("client creation must succeed"); } #[test] @@ -353,10 +354,10 @@ mod tests { match parsed { crate::KbSolanaWsTypedNotification::Root(root) => { assert_eq!(root, 123); - } + }, other => { panic!("unexpected parsed notification: {other:?}"); - } + }, } } @@ -382,10 +383,10 @@ mod tests { assert_eq!(slot_info.parent, 10); assert_eq!(slot_info.root, 11); assert_eq!(slot_info.slot, 12); - } + }, other => { panic!("unexpected parsed notification: {other:?}"); - } + }, } } @@ -396,10 +397,10 @@ mod tests { .account_subscribe_typed("11111111111111111111111111111111".to_string(), None) .await; match result { - Err(crate::KbError::NotConnected(_)) => {} + Err(crate::KbError::NotConnected(_)) => {}, other => { panic!("unexpected result: {other:?}"); - } + }, } } @@ -413,10 +414,10 @@ mod tests { ) .await; match result { - Err(crate::KbError::NotConnected(_)) => {} + Err(crate::KbError::NotConnected(_)) => {}, other => { panic!("unexpected result: {other:?}"); - } + }, } } } diff --git a/kb_lib/src/token_backfill.rs b/kb_lib/src/token_backfill.rs index c44d006..563af0f 100644 --- a/kb_lib/src/token_backfill.rs +++ b/kb_lib/src/token_backfill.rs @@ -82,6 +82,7 @@ pub struct KbTokenBackfillService { wallet_observation_service: crate::KbWalletObservationService, trade_aggregation_service: crate::KbTradeAggregationService, pair_candle_aggregation_service: crate::KbPairCandleAggregationService, + token_metadata_service: crate::KbTokenMetadataBackfillService, } impl KbTokenBackfillService { @@ -101,7 +102,12 @@ impl KbTokenBackfillService { let trade_aggregation_service = crate::KbTradeAggregationService::new(database.clone()); let pair_candle_aggregation_service = crate::KbPairCandleAggregationService::new(database.clone()); - Self { + let token_metadata_service = crate::KbTokenMetadataBackfillService::new( + http_pool.clone(), + database.clone(), + http_role.clone(), + ); + return Self { http_pool, database, persistence, @@ -114,7 +120,8 @@ impl KbTokenBackfillService { wallet_observation_service, trade_aggregation_service, pair_candle_aggregation_service, - } + token_metadata_service, + }; } /// Replays the historical activity of one token mint through the existing pipeline. @@ -195,6 +202,7 @@ impl KbTokenBackfillService { kb_merge_token_backfill_signature_result(&mut result, replay_result); } } + self.backfill_missing_token_metadata_best_effort(100).await; let summary_payload = serde_json::json!({ "tokenMint": result.token_mint, "mintSignatureCount": result.mint_signature_count, @@ -240,7 +248,7 @@ impl KbTokenBackfillService { if let Err(error) = signal_result { return Err(error); } - Ok(result) + return Ok(result); } async fn fetch_signatures_for_address( @@ -258,9 +266,10 @@ impl KbTokenBackfillService { commitment: None, min_context_slot: None, }; - self.http_pool + return self + .http_pool .get_signatures_for_address_for_role(self.http_role.as_str(), address, Some(config)) - .await + .await; } async fn collect_pool_addresses_for_token_mint( @@ -283,7 +292,7 @@ impl KbTokenBackfillService { "token '{}' has no internal id", token.mint ))); - } + }, }; let pools_result = crate::list_pools(self.database.as_ref()).await; let pools = match pools_result { @@ -316,7 +325,7 @@ impl KbTokenBackfillService { } } addresses.sort(); - Ok(addresses) + return Ok(addresses); } async fn replay_signature( @@ -424,7 +433,7 @@ impl KbTokenBackfillService { Ok(pair_candle_aggregations) => pair_candle_aggregations, Err(error) => return Err(error), }; - Ok(KbTokenBackfillSignatureResult { + return Ok(KbTokenBackfillSignatureResult { resolved_transaction_count: 1, missing_transaction_count: 0, decoded_event_count: decoded.len(), @@ -434,7 +443,7 @@ impl KbTokenBackfillService { wallet_participation_count: wallet_observations.len(), trade_event_count: trade_aggregations.len(), pair_candle_count: pair_candle_aggregations.len(), - }) + }); } /// Replays the historical activity of one pool address through the existing pipeline. @@ -443,11 +452,7 @@ impl KbTokenBackfillService { pool_address: &str, pool_signature_limit: usize, ) -> Result { - let effective_limit = if pool_signature_limit > 1000 { - 1000 - } else { - pool_signature_limit - }; + let effective_limit = if pool_signature_limit > 1000 { 1000 } else { pool_signature_limit }; let mut result = crate::KbPoolBackfillResult { pool_address: pool_address.to_string(), pool_signature_count: 0, @@ -466,9 +471,7 @@ impl KbTokenBackfillService { let mut addresses_to_scan = std::vec::Vec::::new(); let trimmed_pool_address = pool_address.trim().to_string(); if trimmed_pool_address.is_empty() { - return Err(crate::KbError::Config( - "pool_address must not be empty".to_string(), - )); + return Err(crate::KbError::Config("pool_address must not be empty".to_string())); } seen_addresses.insert(trimmed_pool_address.clone()); addresses_to_scan.push(trimmed_pool_address.clone()); @@ -486,7 +489,7 @@ impl KbTokenBackfillService { "pool '{}' has no internal id", pool.address ))); - } + }, }; let pool_tokens_result = crate::list_pool_tokens_by_pool_id(self.database.as_ref(), pool_id).await; @@ -512,9 +515,8 @@ impl KbTokenBackfillService { } let mut seen_signatures = std::collections::HashSet::::new(); for address in &addresses_to_scan { - let signatures_result = self - .fetch_signatures_for_address(address.clone(), effective_limit) - .await; + let signatures_result = + self.fetch_signatures_for_address(address.clone(), effective_limit).await; let mut signatures = match signatures_result { Ok(signatures) => signatures, Err(error) => return Err(error), @@ -546,6 +548,7 @@ impl KbTokenBackfillService { result.pair_candle_count += replay_result.pair_candle_count; } } + self.backfill_missing_token_metadata_best_effort(100).await; let summary_payload = serde_json::json!({ "poolAddress": result.pool_address, "poolSignatureCount": result.pool_signature_count, @@ -591,7 +594,33 @@ impl KbTokenBackfillService { if let Err(error) = signal_result { return Err(error); } - Ok(result) + return Ok(result); + } + + async fn backfill_missing_token_metadata_best_effort(&self, limit: i64) { + let metadata_result = + self.token_metadata_service.backfill_missing_token_metadata(Some(limit)).await; + match metadata_result { + Ok(metadata_result) => { + tracing::debug!( + total_token_count = metadata_result.total_token_count, + attempted_token_count = metadata_result.attempted_token_count, + local_metadata_count = metadata_result.local_metadata_count, + mint_account_metadata_count = metadata_result.mint_account_metadata_count, + metaplex_metadata_count = metadata_result.metaplex_metadata_count, + updated_token_count = metadata_result.updated_token_count, + skipped_token_count = metadata_result.skipped_token_count, + error_count = metadata_result.error_count, + "token metadata backfill completed after historical replay" + ); + }, + Err(error) => { + tracing::warn!( + error = %error, + "token metadata backfill failed after historical replay" + ); + }, + } } } @@ -880,10 +909,10 @@ mod tests { } } }); - Self { + return Self { url: format!("http://{}", local_addr), shutdown_tx: Some(shutdown_tx), - } + }; } async fn shutdown(mut self) { let shutdown_tx_option = self.shutdown_tx.take(); @@ -917,11 +946,11 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } fn make_http_endpoint_config(url: std::string::String) -> crate::KbHttpEndpointConfig { - crate::KbHttpEndpointConfig { + return crate::KbHttpEndpointConfig { name: "backfill_http".to_string(), enabled: true, provider: "test".to_string(), @@ -939,7 +968,7 @@ mod tests { max_idle_connections_per_host: 8, pause_after_http_429_ms: None, max_concurrent_requests_per_endpoint: 16, - } + }; } #[tokio::test] @@ -959,9 +988,7 @@ mod tests { database.clone(), "history_backfill".to_string(), ); - let backfill_result = service - .backfill_token_by_mint("BackfillToken111", 20, 20) - .await; + let backfill_result = service.backfill_token_by_mint("BackfillToken111", 20, 20).await; let backfill = match backfill_result { Ok(backfill) => backfill, Err(error) => panic!("backfill must succeed: {}", error), @@ -1059,16 +1086,12 @@ mod tests { database.clone(), "history_backfill".to_string(), ); - let first_result = service - .backfill_token_by_mint("BackfillToken111", 20, 20) - .await; + let first_result = service.backfill_token_by_mint("BackfillToken111", 20, 20).await; if let Err(error) = first_result { panic!("first backfill must succeed: {}", error); } - let second_result = service - .backfill_token_by_mint("BackfillToken111", 20, 20) - .await; + let second_result = service.backfill_token_by_mint("BackfillToken111", 20, 20).await; if let Err(error) = second_result { panic!("second backfill must succeed: {}", error); } diff --git a/kb_lib/src/token_metadata.rs b/kb_lib/src/token_metadata.rs new file mode 100644 index 0000000..051fcf4 --- /dev/null +++ b/kb_lib/src/token_metadata.rs @@ -0,0 +1,1024 @@ +// file: kb_lib/src/token_metadata.rs + +//! Token metadata resolution and backfill. +//! +//! This module enriches already discovered token mints with stable metadata. +//! It intentionally stays independent from DEX-specific decoding so every DEX +//! benefits from the same metadata path. + +const KB_NATIVE_SOL_MINT_ALIAS: &str = "SOL"; +const KB_NATIVE_SOL_SYMBOL: &str = "SOL"; +const KB_NATIVE_SOL_NAME: &str = "Solana"; +const KB_WRAPPED_SOL_SYMBOL: &str = "WSOL"; +const KB_WRAPPED_SOL_NAME: &str = "Wrapped SOL"; +const KB_METAPLEX_TOKEN_METADATA_PROGRAM_ID: &str = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"; + +/// Summary produced by a token metadata backfill pass. +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct KbTokenMetadataBackfillResult { + /// Number of tokens considered by this pass. + pub total_token_count: usize, + /// Number of tokens for which a resolution attempt was made. + pub attempted_token_count: usize, + /// Number of tokens enriched from local deterministic metadata. + pub local_metadata_count: usize, + /// Number of tokens enriched from Pump.fun decoded payloads. + pub pump_fun_payload_metadata_count: usize, + /// Number of tokens enriched from the SPL mint account. + pub mint_account_metadata_count: usize, + /// Number of tokens enriched from the Metaplex metadata account. + pub metaplex_metadata_count: usize, + /// Number of token rows updated. + pub updated_token_count: usize, + /// Number of token rows already complete or not resolvable without error. + pub skipped_token_count: usize, + /// Number of non-fatal per-token errors. + pub error_count: usize, + /// Number of pair display symbols updated after metadata enrichment. + pub pair_symbol_updated_count: usize, + /// Number of pair display symbols already correct after metadata enrichment. + pub pair_symbol_skipped_count: usize, + /// Number of pair display symbols skipped because a related token row was missing. + pub pair_symbol_missing_token_count: usize, +} + +impl KbTokenMetadataBackfillResult { + fn merge(&mut self, other: &KbTokenMetadataBackfillResult) { + self.total_token_count += other.total_token_count; + self.attempted_token_count += other.attempted_token_count; + self.local_metadata_count += other.local_metadata_count; + self.pump_fun_payload_metadata_count += other.pump_fun_payload_metadata_count; + self.mint_account_metadata_count += other.mint_account_metadata_count; + self.metaplex_metadata_count += other.metaplex_metadata_count; + self.updated_token_count += other.updated_token_count; + self.skipped_token_count += other.skipped_token_count; + self.error_count += other.error_count; + self.pair_symbol_updated_count += other.pair_symbol_updated_count; + self.pair_symbol_skipped_count += other.pair_symbol_skipped_count; + self.pair_symbol_missing_token_count += other.pair_symbol_missing_token_count; + } +} + +/// Service that enriches persisted token rows with mint and display metadata. +#[derive(Debug, Clone)] +pub struct KbTokenMetadataBackfillService { + database: std::sync::Arc, + http_pool: std::option::Option>, + http_role: std::string::String, +} + +impl KbTokenMetadataBackfillService { + /// Creates a metadata backfill service backed by Solana HTTP RPC. + pub fn new( + http_pool: std::sync::Arc, + database: std::sync::Arc, + http_role: std::string::String, + ) -> Self { + return Self { + database, + http_pool: Some(http_pool), + http_role, + }; + } + + /// Creates a metadata backfill service that can only apply local and DB-derived metadata. + pub fn new_local(database: std::sync::Arc) -> Self { + return Self { + database, + http_pool: None, + http_role: "local_metadata".to_string(), + }; + } + + /// Enriches all tokens whose metadata is incomplete. + pub async fn backfill_missing_token_metadata( + &self, + limit: std::option::Option, + ) -> Result { + let tokens_result = + crate::list_tokens_missing_metadata(self.database.as_ref(), limit).await; + let tokens = match tokens_result { + Ok(tokens) => tokens, + Err(error) => return Err(error), + }; + let mut result = crate::KbTokenMetadataBackfillResult::default(); + for token in tokens { + let token_result = self.backfill_token_metadata_by_mint(token.mint.as_str()).await; + match token_result { + Ok(token_result) => result.merge(&token_result), + Err(error) => { + result.total_token_count += 1; + result.attempted_token_count += 1; + result.error_count += 1; + tracing::warn!( + mint = %token.mint, + error = %error, + "token metadata backfill failed for one mint" + ); + }, + } + } + let pair_symbol_result = crate::kb_refresh_pair_symbols(self.database.as_ref()).await; + match pair_symbol_result { + Ok(pair_symbol_result) => { + result.pair_symbol_updated_count += pair_symbol_result.updated_pair_count; + result.pair_symbol_skipped_count += pair_symbol_result.skipped_pair_count; + result.pair_symbol_missing_token_count += pair_symbol_result.missing_token_count; + }, + Err(error) => { + result.error_count += 1; + tracing::warn!( + error = %error, + "pair symbol refresh failed after token metadata backfill" + ); + }, + } + return Ok(result); + } + + /// Enriches one token mint with local, DEX-payload, mint-account, and Metaplex metadata. + pub async fn backfill_token_metadata_by_mint( + &self, + mint: &str, + ) -> Result { + let trimmed_mint = mint.trim(); + if trimmed_mint.is_empty() { + return Err(crate::KbError::Config( + "token metadata mint must not be empty".to_string(), + )); + } + let mut result = crate::KbTokenMetadataBackfillResult { + total_token_count: 1, + attempted_token_count: 1, + local_metadata_count: 0, + pump_fun_payload_metadata_count: 0, + mint_account_metadata_count: 0, + metaplex_metadata_count: 0, + updated_token_count: 0, + skipped_token_count: 0, + error_count: 0, + pair_symbol_updated_count: 0, + pair_symbol_skipped_count: 0, + pair_symbol_missing_token_count: 0, + }; + let token_result = crate::get_token_by_mint(self.database.as_ref(), trimmed_mint).await; + let token_option = match token_result { + Ok(token_option) => token_option, + Err(error) => return Err(error), + }; + let token_existed = token_option.is_some(); + let mut token = match token_option { + Some(token) => token, + None => kb_build_empty_token_dto(trimmed_mint), + }; + let original_token = token.clone(); + let mut resolved = KbResolvedTokenMetadata::default(); + let local_metadata_option = kb_resolve_local_token_metadata(trimmed_mint); + if let Some(local_metadata) = local_metadata_option { + result.local_metadata_count += 1; + resolved.merge(local_metadata); + } + let pump_fun_metadata_result = + kb_resolve_pump_fun_metadata_from_decoded_events(self.database.as_ref(), trimmed_mint) + .await; + match pump_fun_metadata_result { + Ok(pump_fun_metadata_option) => { + if let Some(pump_fun_metadata) = pump_fun_metadata_option { + result.pump_fun_payload_metadata_count += 1; + resolved.merge(pump_fun_metadata); + } + }, + Err(error) => { + result.error_count += 1; + tracing::warn!( + mint = %trimmed_mint, + error = %error, + "pump.fun metadata payload resolution failed" + ); + }, + } + if let Some(http_pool) = &self.http_pool { + let mint_account_result = kb_fetch_mint_account_metadata( + http_pool.as_ref(), + self.http_role.as_str(), + trimmed_mint, + ) + .await; + match mint_account_result { + Ok(mint_account_option) => { + if let Some(mint_account) = mint_account_option { + result.mint_account_metadata_count += 1; + resolved.merge(mint_account); + } + }, + Err(error) => { + result.error_count += 1; + tracing::warn!( + mint = %trimmed_mint, + error = %error, + "mint account metadata resolution failed" + ); + }, + } + if kb_should_try_metaplex_metadata(&token, &resolved) { + let metaplex_result = kb_fetch_metaplex_metadata( + http_pool.as_ref(), + self.http_role.as_str(), + trimmed_mint, + ) + .await; + match metaplex_result { + Ok(metaplex_option) => { + if let Some(metaplex_metadata) = metaplex_option { + result.metaplex_metadata_count += 1; + resolved.merge(metaplex_metadata); + } + }, + Err(error) => { + result.error_count += 1; + tracing::warn!( + mint = %trimmed_mint, + error = %error, + "metaplex metadata resolution failed" + ); + }, + } + } + } + let changed = kb_apply_resolved_metadata_to_token(&mut token, &resolved); + if !token_existed && !changed { + result.skipped_token_count += 1; + return Ok(result); + } + if changed || token.id.is_none() { + token.updated_at = chrono::Utc::now(); + let upsert_result = crate::upsert_token(self.database.as_ref(), &token).await; + match upsert_result { + Ok(_) => { + if changed || original_token.id.is_none() { + result.updated_token_count += 1; + } else { + result.skipped_token_count += 1; + } + }, + Err(error) => return Err(error), + } + } else { + result.skipped_token_count += 1; + } + return Ok(result); + } +} + +#[derive(Debug, Clone, Default)] +struct KbResolvedTokenMetadata { + symbol: std::option::Option, + name: std::option::Option, + decimals: std::option::Option, + token_program: std::option::Option, + is_quote_token: std::option::Option, +} + +impl KbResolvedTokenMetadata { + fn merge(&mut self, other: KbResolvedTokenMetadata) { + if kb_option_string_is_missing(self.symbol.as_deref()) && other.symbol.is_some() { + self.symbol = other.symbol; + } + if kb_option_string_is_missing(self.name.as_deref()) && other.name.is_some() { + self.name = other.name; + } + if self.decimals.is_none() && other.decimals.is_some() { + self.decimals = other.decimals; + } + if kb_option_string_is_missing(self.token_program.as_deref()) + && other.token_program.is_some() + { + self.token_program = other.token_program; + } + if self.is_quote_token.is_none() && other.is_quote_token.is_some() { + self.is_quote_token = other.is_quote_token; + } + } +} + +fn kb_build_empty_token_dto(mint: &str) -> crate::KbTokenDto { + return crate::KbTokenDto::new( + mint.to_string(), + None, + None, + None, + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + false, + ); +} + +fn kb_resolve_local_token_metadata(mint: &str) -> std::option::Option { + if mint == KB_NATIVE_SOL_MINT_ALIAS { + return Some(KbResolvedTokenMetadata { + symbol: Some(KB_NATIVE_SOL_SYMBOL.to_string()), + name: Some(KB_NATIVE_SOL_NAME.to_string()), + decimals: Some(9), + token_program: Some(crate::SYSTEM_PROGRAM_ID.to_string()), + is_quote_token: Some(true), + }); + } + let wsol_mint = crate::WSOL_MINT_ID.to_string(); + if mint == wsol_mint { + return Some(KbResolvedTokenMetadata { + symbol: Some(KB_WRAPPED_SOL_SYMBOL.to_string()), + name: Some(KB_WRAPPED_SOL_NAME.to_string()), + decimals: Some(9), + token_program: Some(crate::SPL_TOKEN_PROGRAM_ID.to_string()), + is_quote_token: Some(true), + }); + } + return None; +} + +async fn kb_resolve_pump_fun_metadata_from_decoded_events( + database: &crate::KbDatabase, + mint: &str, +) -> Result, crate::KbError> { + let payload_result = crate::get_latest_pump_fun_create_payload_by_mint(database, mint).await; + let payload_option = match payload_result { + Ok(payload_option) => payload_option, + Err(error) => return Err(error), + }; + let payload_text = match payload_option { + Some(payload_text) => payload_text, + None => return Ok(None), + }; + let payload_result = serde_json::from_str::(payload_text.as_str()); + let payload = match payload_result { + Ok(payload) => payload, + Err(error) => { + return Err(crate::KbError::Json(format!( + "cannot parse pump.fun metadata payload for mint '{}': {}", + mint, error + ))); + }, + }; + return Ok(kb_extract_pump_fun_metadata_from_payload(&payload)); +} + +fn kb_extract_pump_fun_metadata_from_payload( + payload: &serde_json::Value, +) -> std::option::Option { + let symbol = kb_extract_string_by_candidate_keys(payload, &["symbol", "tokenSymbol"]); + let name = kb_extract_string_by_candidate_keys(payload, &["name", "tokenName"]); + let decimals = kb_extract_u8_by_candidate_keys(payload, &["decimals", "tokenDecimals"]); + if symbol.is_none() && name.is_none() && decimals.is_none() { + return None; + } + return Some(KbResolvedTokenMetadata { + symbol, + name, + decimals, + token_program: None, + is_quote_token: None, + }); +} + +fn kb_should_try_metaplex_metadata( + token: &crate::KbTokenDto, + resolved: &KbResolvedTokenMetadata, +) -> bool { + let missing_symbol = kb_option_string_is_missing(token.symbol.as_deref()) + && kb_option_string_is_missing(resolved.symbol.as_deref()); + let missing_name = kb_option_string_is_missing(token.name.as_deref()) + && kb_option_string_is_missing(resolved.name.as_deref()); + return missing_symbol || missing_name; +} + +fn kb_apply_resolved_metadata_to_token( + token: &mut crate::KbTokenDto, + resolved: &KbResolvedTokenMetadata, +) -> bool { + let mut changed = false; + if kb_option_string_is_missing(token.symbol.as_deref()) { + if let Some(symbol) = &resolved.symbol { + if !symbol.trim().is_empty() { + token.symbol = Some(symbol.trim().to_string()); + changed = true; + } + } + } + if kb_option_string_is_missing(token.name.as_deref()) { + if let Some(name) = &resolved.name { + if !name.trim().is_empty() { + token.name = Some(name.trim().to_string()); + changed = true; + } + } + } + if token.decimals.is_none() { + if let Some(decimals) = resolved.decimals { + token.decimals = Some(decimals); + changed = true; + } + } + if let Some(token_program) = &resolved.token_program { + if !token_program.trim().is_empty() && token.token_program != *token_program { + token.token_program = token_program.clone(); + changed = true; + } + } + if let Some(is_quote_token) = resolved.is_quote_token { + if token.is_quote_token != is_quote_token { + token.is_quote_token = is_quote_token; + changed = true; + } + } + return changed; +} + +async fn kb_fetch_mint_account_metadata( + http_pool: &crate::HttpEndpointPool, + http_role: &str, + mint: &str, +) -> Result, crate::KbError> { + let config = serde_json::json!({ + "encoding": "jsonParsed", + "commitment": "confirmed" + }); + let account_result = http_pool + .get_account_info_raw_for_role(http_role, mint.to_string(), Some(config)) + .await; + let account_value = match account_result { + Ok(account_value) => account_value, + Err(error) => return Err(error), + }; + let value_option = account_value.get("value"); + let value = match value_option { + Some(value) => value, + None => return Ok(None), + }; + if value.is_null() { + return Ok(None); + } + let owner = value + .get("owner") + .and_then(serde_json::Value::as_str) + .map(|value| return value.to_string()); + let decimals = value + .get("data") + .and_then(|data| return data.get("parsed")) + .and_then(|parsed| return parsed.get("info")) + .and_then(|info| return info.get("decimals")) + .and_then(serde_json::Value::as_u64) + .and_then(kb_u64_to_u8); + let token_2022_metadata = kb_extract_token_2022_metadata_from_mint_account_value(value); + let mut resolved = KbResolvedTokenMetadata { + symbol: None, + name: None, + decimals, + token_program: owner, + is_quote_token: None, + }; + if let Some(token_2022_metadata) = token_2022_metadata { + resolved.merge(token_2022_metadata); + } + if resolved.symbol.is_none() + && resolved.name.is_none() + && resolved.decimals.is_none() + && resolved.token_program.is_none() + { + return Ok(None); + } + return Ok(Some(resolved)); +} + +fn kb_extract_token_2022_metadata_from_mint_account_value( + value: &serde_json::Value, +) -> std::option::Option { + let extensions_option = value + .get("data") + .and_then(|data| return data.get("parsed")) + .and_then(|parsed| return parsed.get("info")) + .and_then(|info| return info.get("extensions")) + .and_then(serde_json::Value::as_array); + let extensions = match extensions_option { + Some(extensions) => extensions, + None => return None, + }; + for extension in extensions { + let extension_name_option = extension.get("extension").and_then(serde_json::Value::as_str); + let extension_name = match extension_name_option { + Some(extension_name) => extension_name, + None => continue, + }; + if extension_name != "tokenMetadata" { + continue; + } + let state_option = extension + .get("state") + .or_else(|| return extension.get("metadata")) + .or_else(|| return extension.get("value")); + let state = match state_option { + Some(state) => state, + None => continue, + }; + let symbol = kb_extract_string_by_candidate_keys(state, &["symbol", "tokenSymbol"]); + let name = kb_extract_string_by_candidate_keys(state, &["name", "tokenName"]); + if symbol.is_none() && name.is_none() { + continue; + } + return Some(KbResolvedTokenMetadata { + symbol, + name, + decimals: None, + token_program: None, + is_quote_token: None, + }); + } + return None; +} + +async fn kb_fetch_metaplex_metadata( + http_pool: &crate::HttpEndpointPool, + http_role: &str, + mint: &str, +) -> Result, crate::KbError> { + let metadata_address_result = kb_derive_metaplex_metadata_address(mint); + let metadata_address = match metadata_address_result { + Ok(metadata_address) => metadata_address, + Err(error) => return Err(error), + }; + let config = serde_json::json!({ + "encoding": "base64", + "commitment": "confirmed" + }); + let account_result = http_pool + .get_account_info_raw_for_role(http_role, metadata_address, Some(config)) + .await; + let account_value = match account_result { + Ok(account_value) => account_value, + Err(error) => return Err(error), + }; + let value_option = account_value.get("value"); + let value = match value_option { + Some(value) => value, + None => return Ok(None), + }; + if value.is_null() { + return Ok(None); + } + let data_text_option = kb_extract_base64_account_data(value); + let data_text = match data_text_option { + Some(data_text) => data_text, + None => return Ok(None), + }; + let bytes_result = kb_decode_base64_standard(data_text.as_str()); + let bytes = match bytes_result { + Ok(bytes) => bytes, + Err(error) => return Err(error), + }; + return Ok(kb_parse_metaplex_token_metadata_account(&bytes)); +} + +fn kb_derive_metaplex_metadata_address(mint: &str) -> Result { + let program_id_result = ::from_str( + KB_METAPLEX_TOKEN_METADATA_PROGRAM_ID, + ); + let program_id = match program_id_result { + Ok(program_id) => program_id, + Err(error) => { + return Err(crate::KbError::Config(format!( + "invalid metaplex metadata program id '{}': {}", + KB_METAPLEX_TOKEN_METADATA_PROGRAM_ID, error + ))); + }, + }; + let mint_pubkey_result = ::from_str(mint); + let mint_pubkey = match mint_pubkey_result { + Ok(mint_pubkey) => mint_pubkey, + Err(error) => { + return Err(crate::KbError::Config(format!( + "invalid token mint '{}': {}", + mint, error + ))); + }, + }; + let (metadata_address, _) = solana_sdk::pubkey::Pubkey::find_program_address( + &[b"metadata", program_id.as_ref(), mint_pubkey.as_ref()], + &program_id, + ); + return Ok(metadata_address.to_string()); +} + +fn kb_extract_base64_account_data( + value: &serde_json::Value, +) -> std::option::Option { + let data = match value.get("data") { + Some(data) => data, + None => return None, + }; + if let Some(data_array) = data.as_array() { + let first = match data_array.first() { + Some(first) => first, + None => return None, + }; + return first.as_str().map(|value| return value.to_string()); + } + return data.as_str().map(|value| return value.to_string()); +} + +fn kb_parse_metaplex_token_metadata_account( + bytes: &[u8], +) -> std::option::Option { + if bytes.len() < 69 { + return None; + } + let mut offset = 65usize; + let name_option = kb_read_borsh_string(bytes, &mut offset); + let symbol_option = kb_read_borsh_string(bytes, &mut offset); + let _uri_option = kb_read_borsh_string(bytes, &mut offset); + let name = match name_option { + Some(name) => kb_clean_metaplex_string(name.as_str()), + None => None, + }; + let symbol = match symbol_option { + Some(symbol) => kb_clean_metaplex_string(symbol.as_str()), + None => None, + }; + if name.is_none() && symbol.is_none() { + return None; + } + return Some(KbResolvedTokenMetadata { + symbol, + name, + decimals: None, + token_program: None, + is_quote_token: None, + }); +} + +fn kb_read_borsh_string( + bytes: &[u8], + offset: &mut usize, +) -> std::option::Option { + if bytes.len() < *offset + 4 { + return None; + } + let length = u32::from_le_bytes([ + bytes[*offset], + bytes[*offset + 1], + bytes[*offset + 2], + bytes[*offset + 3], + ]) as usize; + *offset += 4; + if bytes.len() < *offset + length { + return None; + } + let data = &bytes[*offset..*offset + length]; + *offset += length; + let text_result = std::string::String::from_utf8(data.to_vec()); + match text_result { + Ok(text) => return Some(text), + Err(_) => return None, + } +} + +fn kb_clean_metaplex_string(value: &str) -> std::option::Option { + let cleaned = value.trim_matches(char::from(0)).trim().to_string(); + if cleaned.is_empty() { return None } else { return Some(cleaned) } +} + +fn kb_decode_base64_standard(text: &str) -> Result, crate::KbError> { + let mut output = std::vec::Vec::new(); + let mut group = [0u8; 4]; + let mut group_len = 0usize; + let mut padding_count = 0usize; + for byte in text.bytes() { + if byte == b'\r' || byte == b'\n' || byte == b'\t' || byte == b' ' { + continue; + } + let value_option = kb_base64_value(byte); + let value = match value_option { + Some(value) => value, + None => { + return Err(crate::KbError::Json(format!( + "invalid base64 character '{}'", + byte as char + ))); + }, + }; + if byte == b'=' { + padding_count += 1; + } + group[group_len] = value; + group_len += 1; + if group_len == 4 { + output.push((group[0] << 2) | (group[1] >> 4)); + if padding_count < 2 { + output.push((group[1] << 4) | (group[2] >> 2)); + } + if padding_count == 0 { + output.push((group[2] << 6) | group[3]); + } + group = [0u8; 4]; + group_len = 0; + padding_count = 0; + } + } + if group_len != 0 { + return Err(crate::KbError::Json( + "invalid base64 length: trailing partial group".to_string(), + )); + } + return Ok(output); +} + +fn kb_base64_value(byte: u8) -> std::option::Option { + match byte { + b'A'..=b'Z' => return Some(byte - b'A'), + b'a'..=b'z' => return Some(byte - b'a' + 26), + b'0'..=b'9' => return Some(byte - b'0' + 52), + b'+' => return Some(62), + b'/' => return Some(63), + b'=' => return Some(0), + _ => return None, + } +} + +fn kb_extract_string_by_candidate_keys( + payload: &serde_json::Value, + candidate_keys: &[&str], +) -> std::option::Option { + for key in candidate_keys { + let value_option = payload.get(*key); + let value = match value_option { + Some(value) => value, + None => continue, + }; + if let Some(text) = value.as_str() { + let trimmed = text.trim(); + if !trimmed.is_empty() { + return Some(trimmed.to_string()); + } + continue; + } + if value.is_number() || value.is_boolean() { + return Some(value.to_string()); + } + } + return None; +} + +fn kb_extract_u8_by_candidate_keys( + payload: &serde_json::Value, + candidate_keys: &[&str], +) -> std::option::Option { + for key in candidate_keys { + let value_option = payload.get(*key); + let value = match value_option { + Some(value) => value, + None => continue, + }; + if let Some(number) = value.as_u64() { + let converted = kb_u64_to_u8(number); + if converted.is_some() { + return converted; + } + } + if let Some(text) = value.as_str() { + let parsed_result = text.trim().parse::(); + let parsed = match parsed_result { + Ok(parsed) => parsed, + Err(_) => continue, + }; + let converted = kb_u64_to_u8(parsed); + if converted.is_some() { + return converted; + } + } + } + return None; +} + +fn kb_option_string_is_missing(value: std::option::Option<&str>) -> bool { + match value { + Some(value) => return value.trim().is_empty(), + None => return true, + } +} + +fn kb_u64_to_u8(value: u64) -> std::option::Option { + let converted_result = u8::try_from(value); + match converted_result { + Ok(converted) => return Some(converted), + Err(_) => return None, + } +} + +#[cfg(test)] +mod tests { + fn build_test_metadata_account(name: &str, symbol: &str, uri: &str) -> std::vec::Vec { + let mut bytes = std::vec::Vec::new(); + bytes.push(4_u8); + bytes.extend_from_slice(&[1_u8; 32]); + bytes.extend_from_slice(&[2_u8; 32]); + kb_push_borsh_string(&mut bytes, name); + kb_push_borsh_string(&mut bytes, symbol); + kb_push_borsh_string(&mut bytes, uri); + return bytes; + } + + fn kb_push_borsh_string(bytes: &mut std::vec::Vec, value: &str) { + let length = value.len() as u32; + bytes.extend_from_slice(&length.to_le_bytes()); + bytes.extend_from_slice(value.as_bytes()); + } + + async fn make_database() -> std::sync::Arc { + let tempdir_result = tempfile::tempdir(); + let tempdir = match tempdir_result { + Ok(tempdir) => tempdir, + Err(error) => panic!("tempdir must succeed: {}", error), + }; + let database_path = tempdir.path().join("token_metadata.sqlite3"); + let config = crate::KbDatabaseConfig { + enabled: true, + backend: crate::KbDatabaseBackend::Sqlite, + sqlite: crate::KbSqliteDatabaseConfig { + path: database_path.to_string_lossy().to_string(), + create_if_missing: true, + busy_timeout_ms: 5000, + max_connections: 1, + auto_initialize_schema: true, + use_wal: true, + }, + }; + let database_result = crate::KbDatabase::connect_and_initialize(&config).await; + let database = match database_result { + Ok(database) => database, + Err(error) => panic!("database init must succeed: {}", error), + }; + return std::sync::Arc::new(database); + } + + #[test] + fn local_metadata_resolves_wsol() { + let mint = crate::WSOL_MINT_ID.to_string(); + let metadata_option = super::kb_resolve_local_token_metadata(mint.as_str()); + let metadata = match metadata_option { + Some(metadata) => metadata, + None => panic!("WSOL metadata must resolve"), + }; + assert_eq!(metadata.symbol.as_deref(), Some("WSOL")); + assert_eq!(metadata.name.as_deref(), Some("Wrapped SOL")); + assert_eq!(metadata.decimals, Some(9)); + assert_eq!(metadata.is_quote_token, Some(true)); + } + + #[test] + fn pump_fun_payload_metadata_extracts_name_and_symbol() { + let payload = serde_json::json!({ + "mint": "PumpMint111", + "symbol": "PUMPX", + "name": "Pump Example", + "uri": "https://example.invalid/pump.json" + }); + let metadata_option = super::kb_extract_pump_fun_metadata_from_payload(&payload); + let metadata = match metadata_option { + Some(metadata) => metadata, + None => panic!("pump.fun metadata must parse"), + }; + assert_eq!(metadata.symbol.as_deref(), Some("PUMPX")); + assert_eq!(metadata.name.as_deref(), Some("Pump Example")); + } + + #[test] + fn token_2022_inline_metadata_extracts_name_and_symbol() { + let account = serde_json::json!({ + "data": { + "parsed": { + "info": { + "extensions": [ + { + "extension": "tokenMetadata", + "state": { + "symbol": "T22", + "name": "Token 2022 Example" + } + } + ] + } + } + } + }); + let metadata_option = + super::kb_extract_token_2022_metadata_from_mint_account_value(&account); + let metadata = match metadata_option { + Some(metadata) => metadata, + None => panic!("token-2022 metadata must parse"), + }; + assert_eq!(metadata.symbol.as_deref(), Some("T22")); + assert_eq!(metadata.name.as_deref(), Some("Token 2022 Example")); + } + + #[test] + fn base64_decoder_decodes_standard_payload() { + let decoded_result = super::kb_decode_base64_standard("AQIDBA=="); + let decoded = match decoded_result { + Ok(decoded) => decoded, + Err(error) => panic!("base64 decode must succeed: {}", error), + }; + assert_eq!(decoded, vec![1_u8, 2_u8, 3_u8, 4_u8]); + } + + #[test] + fn metaplex_parser_extracts_name_and_symbol() { + let bytes = build_test_metadata_account( + "Example Token\0\0\0", + "EXM\0\0", + "https://example.invalid/token.json", + ); + let metadata_option = super::kb_parse_metaplex_token_metadata_account(&bytes); + let metadata = match metadata_option { + Some(metadata) => metadata, + None => panic!("metadata must parse"), + }; + assert_eq!(metadata.name.as_deref(), Some("Example Token")); + assert_eq!(metadata.symbol.as_deref(), Some("EXM")); + } + + #[tokio::test] + async fn local_backfill_updates_wsol_without_http() { + let database = make_database().await; + let token = crate::KbTokenDto::new( + crate::WSOL_MINT_ID.to_string(), + None, + None, + None, + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + false, + ); + let upsert_result = crate::upsert_token(database.as_ref(), &token).await; + if let Err(error) = upsert_result { + panic!("token upsert must succeed: {}", error); + } + let service = crate::KbTokenMetadataBackfillService::new_local(database.clone()); + let result = service.backfill_missing_token_metadata(Some(10)).await; + let result = match result { + Ok(result) => result, + Err(error) => panic!("metadata backfill must succeed: {}", error), + }; + assert_eq!(result.updated_token_count, 1); + let fetched_result = + crate::get_token_by_mint(database.as_ref(), crate::WSOL_MINT_ID.to_string().as_str()) + .await; + let fetched_option = match fetched_result { + Ok(fetched_option) => fetched_option, + Err(error) => panic!("token fetch must succeed: {}", error), + }; + let fetched = match fetched_option { + Some(fetched) => fetched, + None => panic!("token must exist"), + }; + assert_eq!(fetched.symbol.as_deref(), Some("WSOL")); + assert_eq!(fetched.name.as_deref(), Some("Wrapped SOL")); + assert_eq!(fetched.decimals, Some(9)); + assert!(fetched.is_quote_token); + } + + #[tokio::test] + async fn local_backfill_does_not_overwrite_existing_display_metadata() { + let database = make_database().await; + let token = crate::KbTokenDto::new( + crate::WSOL_MINT_ID.to_string(), + Some("SOL".to_string()), + Some("Custom Sol".to_string()), + None, + crate::SPL_TOKEN_PROGRAM_ID.to_string(), + false, + ); + let upsert_result = crate::upsert_token(database.as_ref(), &token).await; + if let Err(error) = upsert_result { + panic!("token upsert must succeed: {}", error); + } + let service = crate::KbTokenMetadataBackfillService::new_local(database.clone()); + let result = service + .backfill_token_metadata_by_mint(crate::WSOL_MINT_ID.to_string().as_str()) + .await; + if let Err(error) = result { + panic!("metadata backfill must succeed: {}", error); + } + let fetched_result = + crate::get_token_by_mint(database.as_ref(), crate::WSOL_MINT_ID.to_string().as_str()) + .await; + let fetched_option = match fetched_result { + Ok(fetched_option) => fetched_option, + Err(error) => panic!("token fetch must succeed: {}", error), + }; + let fetched = match fetched_option { + Some(fetched) => fetched, + None => panic!("token must exist"), + }; + assert_eq!(fetched.symbol.as_deref(), Some("SOL")); + assert_eq!(fetched.name.as_deref(), Some("Custom Sol")); + assert_eq!(fetched.decimals, Some(9)); + assert!(fetched.is_quote_token); + } +} diff --git a/kb_lib/src/tracing.rs b/kb_lib/src/tracing.rs index f91d46e..f0e7a84 100644 --- a/kb_lib/src/tracing.rs +++ b/kb_lib/src/tracing.rs @@ -25,7 +25,7 @@ pub struct KbTracingGuard { impl KbTracingGuard { /// Returns the number of active tracing worker guards. pub fn guard_count(&self) -> usize { - self.guards.len() + return self.guards.len(); } } @@ -48,12 +48,10 @@ pub fn init_tracing(config: &crate::KbLoggingConfig) -> Result Ok(KbTracingGuard { - guards: vec![stdout_guard], - }), - Err(error) => Err(error), + Ok(()) => return Ok(KbTracingGuard { guards: vec![stdout_guard] }), + Err(error) => return Err(error), } - } + }, (false, true) => { let file_writer_result = build_file_writer(config); let (file_non_blocking, file_guard) = match file_writer_result { @@ -68,12 +66,10 @@ pub fn init_tracing(config: &crate::KbLoggingConfig) -> Result Ok(KbTracingGuard { - guards: vec![file_guard], - }), - Err(error) => Err(error), + Ok(()) => return Ok(KbTracingGuard { guards: vec![file_guard] }), + Err(error) => return Err(error), } - } + }, (true, true) => { let (stdout_non_blocking, stdout_guard) = tracing_appender::non_blocking(std::io::stdout()); @@ -92,12 +88,10 @@ pub fn init_tracing(config: &crate::KbLoggingConfig) -> Result Ok(KbTracingGuard { - guards: vec![stdout_guard, file_guard], - }), - Err(error) => Err(error), + Ok(()) => return Ok(KbTracingGuard { guards: vec![stdout_guard, file_guard] }), + Err(error) => return Err(error), } - } + }, (false, false) => { let env_filter_result = build_env_filter(&filter_expression); let env_filter = match env_filter_result { @@ -106,12 +100,14 @@ pub fn init_tracing(config: &crate::KbLoggingConfig) -> Result Ok(KbTracingGuard { guards: vec![] }), - Err(error) => Err(crate::KbError::Tracing(format!( - "cannot initialize tracing subscriber: {error}" - ))), + Ok(()) => return Ok(KbTracingGuard { guards: vec![] }), + Err(error) => { + return Err(crate::KbError::Tracing(format!( + "cannot initialize tracing subscriber: {error}" + ))); + }, } - } + }, } } @@ -121,7 +117,7 @@ fn build_filter_expression(config: &crate::KbLoggingConfig) -> std::string::Stri for (target, level) in &config.target_filters { directives.push(format!("{target}={level}")); } - directives.join(",") + return directives.join(","); } fn build_env_filter( @@ -129,16 +125,18 @@ fn build_env_filter( ) -> Result { let from_env_result = tracing_subscriber::EnvFilter::try_from_default_env(); match from_env_result { - Ok(env_filter) => Ok(env_filter), + Ok(env_filter) => return Ok(env_filter), Err(_) => { let new_result = tracing_subscriber::EnvFilter::try_new(filter_expression); match new_result { - Ok(env_filter) => Ok(env_filter), - Err(error) => Err(crate::KbError::Tracing(format!( - "cannot build env filter from '{filter_expression}': {error}" - ))), + Ok(env_filter) => return Ok(env_filter), + Err(error) => { + return Err(crate::KbError::Tracing(format!( + "cannot build env filter from '{filter_expression}': {error}" + ))); + }, } - } + }, } } @@ -152,7 +150,7 @@ fn resolve_time_format(value: &str) -> std::string::String { if value == "none" { return "%+".to_string(); } - "%+".to_string() + return "%+".to_string(); } fn build_file_writer( @@ -191,10 +189,10 @@ fn build_file_writer( "cannot build rolling file appender in '{}': {error}", directory_path.display() ))); - } + }, }; let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); - Ok((KbStripAnsiMakeWriter::new(non_blocking), guard)) + return Ok((KbStripAnsiMakeWriter::new(non_blocking), guard)); } fn init_single_layer_subscriber( @@ -273,10 +271,12 @@ where .try_init() }; match init_result { - Ok(()) => Ok(()), - Err(error) => Err(crate::KbError::Tracing(format!( - "cannot initialize tracing subscriber: {error}" - ))), + Ok(()) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Tracing(format!( + "cannot initialize tracing subscriber: {error}" + ))); + }, } } @@ -401,10 +401,12 @@ where .try_init() }; match init_result { - Ok(()) => Ok(()), - Err(error) => Err(crate::KbError::Tracing(format!( - "cannot initialize tracing subscriber: {error}" - ))), + Ok(()) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Tracing(format!( + "cannot initialize tracing subscriber: {error}" + ))); + }, } } @@ -414,7 +416,7 @@ struct KbStripAnsiMakeWriter { impl KbStripAnsiMakeWriter { fn new(inner: W) -> Self { - Self { inner } + return Self { inner }; } } @@ -429,9 +431,7 @@ where type Writer = KbStripAnsiWriter; fn make_writer(&'a self) -> Self::Writer { - KbStripAnsiWriter { - inner: self.inner.make_writer(), - } + return KbStripAnsiWriter { inner: self.inner.make_writer() }; } } @@ -442,15 +442,14 @@ where fn write(&mut self, buf: &[u8]) -> std::io::Result { let stripped = kb_strip_ansi_bytes(buf); let write_result = self.inner.write_all(&stripped); - match write_result { - Ok(()) => Ok(buf.len()), - Err(error) => Err(error), + Ok(()) => return Ok(buf.len()), + Err(error) => return Err(error), } } fn flush(&mut self) -> std::io::Result<()> { - self.inner.flush() + return self.inner.flush(); } } @@ -459,24 +458,22 @@ fn kb_strip_ansi_bytes(input: &[u8]) -> std::vec::Vec { let mut index = 0usize; while index < input.len() { let byte = input[index]; - if byte == 0x1B { - if index + 1 < input.len() && input[index + 1] == b'[' { - index += 2; - while index < input.len() { - let current = input[index]; - if (0x40..=0x7E).contains(¤t) { - index += 1; - break; - } + if byte == 0x1B && index + 1 < input.len() && input[index + 1] == b'[' { + index += 2; + while index < input.len() { + let current = input[index]; + if (0x40..=0x7E).contains(¤t) { index += 1; + break; } - continue; + index += 1; } + continue; } output.push(byte); index += 1; } - output + return output; } #[cfg(test)] diff --git a/kb_lib/src/trade_aggregation.rs b/kb_lib/src/trade_aggregation.rs index 8b38571..33334bd 100644 --- a/kb_lib/src/trade_aggregation.rs +++ b/kb_lib/src/trade_aggregation.rs @@ -17,6 +17,12 @@ pub struct KbTradeAggregationResult { pub created_trade_event: bool, } +type KbExtractedTradeAmounts = ( + std::option::Option, + std::option::Option, + std::option::Option, +); + /// Trade-aggregation service. #[derive(Debug, Clone)] pub struct KbTradeAggregationService { @@ -28,10 +34,7 @@ impl KbTradeAggregationService { /// Creates a new trade-aggregation service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Records normalized trade events and updates pair metrics for one transaction signature. @@ -52,7 +55,7 @@ impl KbTradeAggregationService { "cannot aggregate trades for unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { Some(transaction_id) => transaction_id, @@ -61,7 +64,7 @@ impl KbTradeAggregationService { "transaction '{}' has no internal id", signature ))); - } + }, }; let decoded_events_result = crate::list_dex_decoded_events_by_transaction_id( self.database.as_ref(), @@ -83,7 +86,7 @@ impl KbTradeAggregationService { return Err(crate::KbError::InvalidState( "decoded event has no internal id".to_string(), )); - } + }, }; let existing_trade_result = crate::get_trade_event_by_decoded_event_id( self.database.as_ref(), @@ -115,7 +118,7 @@ impl KbTradeAggregationService { "pool '{}' has no internal id", pool.address ))); - } + }, }; let pair_result = crate::get_pair_by_pool_id(self.database.as_ref(), pool_id).await; let pair_option = match pair_result { @@ -133,7 +136,7 @@ impl KbTradeAggregationService { "pair for pool '{}' has no internal id", pool_id ))); - } + }, }; let pool_tokens_result = crate::list_pool_tokens_by_pool_id(self.database.as_ref(), pool_id).await; @@ -158,7 +161,7 @@ impl KbTradeAggregationService { "skipping decoded event with invalid payload_json" ); continue; - } + }, }; if !kb_is_decoded_event_trade_candidate(decoded_event.event_kind.as_str(), &payload) { tracing::debug!( @@ -181,13 +184,7 @@ impl KbTradeAggregationService { let trade_side = kb_extract_trade_side(decoded_event.event_kind.as_str(), &payload); let mut base_amount_raw = kb_extract_amount_string( &payload, - &[ - "baseAmountRaw", - "base_amount_raw", - "baseAmount", - "amountBase", - "amountInBase", - ], + &["baseAmountRaw", "base_amount_raw", "baseAmount", "amountBase", "amountInBase"], ); let mut quote_amount_raw = kb_extract_amount_string( &payload, @@ -377,7 +374,7 @@ impl KbTradeAggregationService { return Err(crate::KbError::InvalidState( "pair metric has no internal id".to_string(), )); - } + }, }; if created_trade_event { let mut updated_metric = existing_metric.clone(); @@ -464,7 +461,7 @@ impl KbTradeAggregationService { created_trade_event, }); } - Ok(results) + return Ok(results); } } @@ -481,7 +478,7 @@ fn kb_is_decoded_event_trade_candidate(event_kind: &str, payload: &serde_json::V if let Some(event_category) = event_category_option { return event_category.as_str() == "trade"; } - kb_is_trade_event_kind(event_kind) + return kb_is_trade_event_kind(event_kind); } fn kb_is_decoded_event_candle_candidate(event_kind: &str, payload: &serde_json::Value) -> bool { @@ -495,7 +492,7 @@ fn kb_is_decoded_event_candle_candidate(event_kind: &str, payload: &serde_json:: if !kb_is_decoded_event_trade_candidate(event_kind, payload) { return false; } - kb_is_trade_event_kind(event_kind) + return kb_is_trade_event_kind(event_kind); } fn kb_extract_top_level_bool_by_candidate_keys( @@ -537,7 +534,7 @@ fn kb_extract_top_level_bool_by_candidate_keys( } } } - None + return None; } fn kb_is_priced_trade_event( @@ -582,7 +579,7 @@ fn kb_is_priced_trade_event( if !price.is_finite() { return false; } - price > 0.0 + return price > 0.0; } fn kb_is_trade_event_kind(event_kind: &str) -> bool { @@ -613,16 +610,16 @@ fn kb_is_trade_event_kind(event_kind: &str) -> bool { if event_kind == "raydium_clmm.exact_output" { return true; } - false + return false; } fn kb_convert_slot_to_i64(slot: std::option::Option) -> std::option::Option { match slot { Some(slot) => match i64::try_from(slot) { - Ok(slot) => Some(slot), - Err(_) => None, + Ok(slot) => return Some(slot), + Err(_) => return None, }, - None => None, + None => return None, } } @@ -636,7 +633,7 @@ fn kb_extract_trade_side(event_kind: &str, payload: &serde_json::Value) -> crate Some("SellBase") => return crate::KbSwapTradeSide::SellBase, Some("sell") => return crate::KbSwapTradeSide::SellBase, Some("SELL") => return crate::KbSwapTradeSide::SellBase, - _ => {} + _ => {}, } if event_kind.ends_with(".buy") { return crate::KbSwapTradeSide::BuyBase; @@ -644,14 +641,14 @@ fn kb_extract_trade_side(event_kind: &str, payload: &serde_json::Value) -> crate if event_kind.ends_with(".sell") { return crate::KbSwapTradeSide::SellBase; } - crate::KbSwapTradeSide::Unknown + return crate::KbSwapTradeSide::Unknown; } fn kb_extract_amount_string( payload: &serde_json::Value, candidate_keys: &[&str], ) -> std::option::Option { - kb_extract_scalar_as_string_by_candidate_keys(payload, candidate_keys) + return kb_extract_scalar_as_string_by_candidate_keys(payload, candidate_keys); } fn kb_apply_trade_to_pair_metric( @@ -693,9 +690,9 @@ fn kb_add_raw_amounts( right: std::option::Option, ) -> std::option::Option { match (left, right) { - (None, None) => None, - (Some(left), None) => Some(left), - (None, Some(right)) => Some(right), + (None, None) => return None, + (Some(left), None) => return Some(left), + (None, Some(right)) => return Some(right), (Some(left), Some(right)) => { let left_value_result = left.parse::(); let left_value = match left_value_result { @@ -707,8 +704,8 @@ fn kb_add_raw_amounts( Ok(right_value) => right_value, Err(_) => return Some(left), }; - Some((left_value + right_value).to_string()) - } + return Some((left_value + right_value).to_string()); + }, } } @@ -742,7 +739,7 @@ fn kb_extract_string_by_candidate_keys( } } } - None + return None; } fn kb_extract_scalar_as_string_by_candidate_keys( @@ -785,7 +782,7 @@ fn kb_extract_scalar_as_string_by_candidate_keys( } } } - None + return None; } fn kb_find_pool_token_vault_address_by_token_id( @@ -806,7 +803,7 @@ fn kb_find_pool_token_vault_address_by_token_id( } return Some(vault_address); } - None + return None; } fn kb_extract_trade_amounts_from_vault_balance_deltas( @@ -814,14 +811,7 @@ fn kb_extract_trade_amounts_from_vault_balance_deltas( meta_json: std::option::Option<&str>, base_vault_address: std::option::Option<&str>, quote_vault_address: std::option::Option<&str>, -) -> Result< - ( - std::option::Option, - std::option::Option, - std::option::Option, - ), - crate::KbError, -> { +) -> Result { let meta_json = match meta_json { Some(meta_json) => meta_json, None => return Ok((None, None, None)), @@ -834,7 +824,7 @@ fn kb_extract_trade_amounts_from_vault_balance_deltas( "cannot parse transaction_json for pump_swap amount extraction: {}", error ))); - } + }, }; let meta_value_result = serde_json::from_str::(meta_json); let meta_value = match meta_value_result { @@ -844,7 +834,7 @@ fn kb_extract_trade_amounts_from_vault_balance_deltas( "cannot parse meta_json for pump_swap amount extraction: {}", error ))); - } + }, }; let account_keys_result = kb_extract_transaction_account_keys(&transaction_value); let account_keys = match account_keys_result { @@ -869,32 +859,29 @@ fn kb_extract_trade_amounts_from_vault_balance_deltas( 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()); + let base_pre_raw = base_pre.map(|value| return value.0.clone()); + let base_post_raw = base_post.map(|value| return 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); + let base_pre_ui = base_pre.and_then(|value| return value.1); + let base_post_ui = base_post.and_then(|value| return value.1); let base_delta_ui = kb_compute_ui_delta_abs(base_pre_ui, base_post_ui); if let Some(quote_vault_address) = quote_vault_address { let quote_pre = pre_balances.get(quote_vault_address); let quote_post = post_balances.get(quote_vault_address); - let quote_pre_raw = quote_pre.map(|value| value.0.clone()); - let quote_post_raw = quote_post.map(|value| value.0.clone()); + let quote_pre_raw = quote_pre.map(|value| return value.0.clone()); + let quote_post_raw = quote_post.map(|value| return value.0.clone()); quote_amount_raw = kb_compute_amount_delta_abs(quote_pre_raw, quote_post_raw); - let quote_pre_ui = quote_pre.and_then(|value| value.1); - let quote_post_ui = quote_post.and_then(|value| value.1); + let quote_pre_ui = quote_pre.and_then(|value| return value.1); + let quote_post_ui = quote_post.and_then(|value| return value.1); let quote_delta_ui = kb_compute_ui_delta_abs(quote_pre_ui, quote_post_ui); - match (base_delta_ui, quote_delta_ui) { - (Some(base_delta_ui), Some(quote_delta_ui)) => { - if base_delta_ui > 0.0 { - price_quote_per_base = Some(quote_delta_ui / base_delta_ui); - } + if let (Some(base_delta_ui), Some(quote_delta_ui)) = (base_delta_ui, quote_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)) + return Ok((base_amount_raw, quote_amount_raw, price_quote_per_base)); } fn kb_extract_pump_fun_amounts_from_transaction( @@ -902,14 +889,7 @@ fn kb_extract_pump_fun_amounts_from_transaction( 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::option::Option, - std::option::Option, - ), - crate::KbError, -> { +) -> Result { let meta_json = match meta_json { Some(meta_json) => meta_json, None => return Ok((None, None, None)), @@ -922,7 +902,7 @@ fn kb_extract_pump_fun_amounts_from_transaction( "cannot parse transaction_json for pump_fun amount extraction: {}", error ))); - } + }, }; let meta_value_result = serde_json::from_str::(meta_json); let meta_value = match meta_value_result { @@ -932,7 +912,7 @@ fn kb_extract_pump_fun_amounts_from_transaction( "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 { @@ -958,11 +938,11 @@ fn kb_extract_pump_fun_amounts_from_transaction( 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()); + let base_pre_raw = base_pre.map(|value| return value.0.clone()); + let base_post_raw = base_post.map(|value| return 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); + let base_pre_ui = base_pre.and_then(|value| return value.1); + let base_post_ui = base_post.and_then(|value| return 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 { @@ -985,7 +965,7 @@ fn kb_extract_pump_fun_amounts_from_transaction( } } } - Ok((base_amount_raw, quote_amount_raw, price_quote_per_base)) + return Ok((base_amount_raw, quote_amount_raw, price_quote_per_base)); } fn kb_extract_native_balance_delta_by_address( @@ -1004,12 +984,10 @@ fn kb_extract_native_balance_delta_by_address( 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_option = + meta_value.get("preBalances").and_then(|value| return value.as_array()); + let post_balances_option = + meta_value.get("postBalances").and_then(|value| return value.as_array()); let pre_balances = match pre_balances_option { Some(pre_balances) => pre_balances, None => return Ok(None), @@ -1034,7 +1012,7 @@ fn kb_extract_native_balance_delta_by_address( if post_balance >= pre_balance { return Ok(Some(post_balance - pre_balance)); } - Ok(Some(pre_balance - post_balance)) + return Ok(Some(pre_balance - post_balance)); } fn kb_extract_transaction_account_keys( @@ -1043,11 +1021,11 @@ fn kb_extract_transaction_account_keys( let candidate_arrays = [ transaction_value .get("message") - .and_then(|value| value.get("accountKeys")), + .and_then(|value| return value.get("accountKeys")), transaction_value .get("transaction") - .and_then(|value| value.get("message")) - .and_then(|value| value.get("accountKeys")), + .and_then(|value| return value.get("message")) + .and_then(|value| return value.get("accountKeys")), transaction_value.get("accountKeys"), ]; for candidate_array_option in candidate_arrays { @@ -1065,7 +1043,7 @@ fn kb_extract_transaction_account_keys( account_keys.push(value.to_string()); continue; } - let pubkey_option = item.get("pubkey").and_then(|value| value.as_str()); + let pubkey_option = item.get("pubkey").and_then(|value| return value.as_str()); if let Some(pubkey) = pubkey_option { account_keys.push(pubkey.to_string()); continue; @@ -1075,9 +1053,9 @@ fn kb_extract_transaction_account_keys( return Ok(account_keys); } } - Err(crate::KbError::Json( + return Err(crate::KbError::Json( "cannot extract accountKeys from transaction_json".to_string(), - )) + )); } fn kb_extract_token_balance_map( @@ -1095,15 +1073,14 @@ fn kb_extract_token_balance_map( std::string::String, (std::string::String, std::option::Option), >::new(); - let balances_option = meta_value - .get(field_name) - .and_then(|value| value.as_array()); + let balances_option = meta_value.get(field_name).and_then(|value| return value.as_array()); let balances = match balances_option { Some(balances) => balances, None => return Ok(result), }; for balance in balances { - let account_index_option = balance.get("accountIndex").and_then(|value| value.as_u64()); + let account_index_option = + balance.get("accountIndex").and_then(|value| return value.as_u64()); let account_index = match account_index_option { Some(account_index) => account_index as usize, None => continue, @@ -1117,16 +1094,14 @@ fn kb_extract_token_balance_map( Some(ui_token_amount) => ui_token_amount, None => continue, }; - let raw_amount_option = ui_token_amount - .get("amount") - .and_then(|value| value.as_str()); + let raw_amount_option = + ui_token_amount.get("amount").and_then(|value| return value.as_str()); let raw_amount = match raw_amount_option { Some(raw_amount) => raw_amount.to_string(), None => continue, }; - let ui_amount_string_option = ui_token_amount - .get("uiAmountString") - .and_then(|value| value.as_str()); + let ui_amount_string_option = + ui_token_amount.get("uiAmountString").and_then(|value| return value.as_str()); let ui_amount = match ui_amount_string_option { Some(ui_amount_string) => { let parse_result = ui_amount_string.parse::(); @@ -1134,12 +1109,12 @@ fn kb_extract_token_balance_map( Ok(ui_amount) => Some(ui_amount), Err(_) => None, } - } + }, None => None, }; result.insert(account_address, (raw_amount, ui_amount)); } - Ok(result) + return Ok(result); } fn kb_compute_amount_delta_abs( @@ -1169,7 +1144,7 @@ fn kb_compute_amount_delta_abs( } else { pre_value - post_value }; - Some(delta.to_string()) + return Some(delta.to_string()); } fn kb_compute_ui_delta_abs( @@ -1189,7 +1164,7 @@ fn kb_compute_ui_delta_abs( } else { pre_amount - post_amount }; - Some(delta) + return Some(delta); } fn kb_compute_price_quote_per_base_from_raw_amounts( @@ -1220,7 +1195,7 @@ fn kb_compute_price_quote_per_base_from_raw_amounts( if base_amount <= 0.0 { return None; } - Some(quote_amount / base_amount) + return Some(quote_amount / base_amount); } fn kb_compute_price_quote_per_base_with_decimals( @@ -1239,7 +1214,7 @@ fn kb_compute_price_quote_per_base_with_decimals( Ok(inferred) => inferred, Err(_) => return None, }; - inferred.2 + return inferred.2; } #[cfg(test)] @@ -1268,7 +1243,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fluxbeam_swap_transaction( @@ -1346,9 +1321,8 @@ mod tests { seed_fluxbeam_swap_transaction(database.clone(), "sig-trade-aggregation-1", "1000", "2500") .await; let service = crate::KbTradeAggregationService::new(database.clone()); - let record_result = service - .record_transaction_by_signature("sig-trade-aggregation-1") - .await; + let record_result = + service.record_transaction_by_signature("sig-trade-aggregation-1").await; let results = match record_result { Ok(results) => results, Err(error) => panic!("trade aggregation must succeed: {}", error), @@ -1379,14 +1353,8 @@ mod tests { assert_eq!(pair_metric.trade_count, 1); assert_eq!(pair_metric.buy_count, 1); assert_eq!(pair_metric.sell_count, 0); - assert_eq!( - pair_metric.cumulative_base_amount_raw, - Some("1000".to_string()) - ); - assert_eq!( - pair_metric.cumulative_quote_amount_raw, - Some("2500".to_string()) - ); + assert_eq!(pair_metric.cumulative_base_amount_raw, Some("1000".to_string())); + assert_eq!(pair_metric.cumulative_quote_amount_raw, Some("2500".to_string())); assert_eq!(pair_metric.last_price_quote_per_base, Some(2.5)); } @@ -1396,18 +1364,15 @@ mod tests { seed_fluxbeam_swap_transaction(database.clone(), "sig-trade-aggregation-2", "1000", "2500") .await; let service = crate::KbTradeAggregationService::new(database.clone()); - let first_result = service - .record_transaction_by_signature("sig-trade-aggregation-2") - .await; + let first_result = service.record_transaction_by_signature("sig-trade-aggregation-2").await; let first_results = match first_result { Ok(first_results) => first_results, Err(error) => panic!("first trade aggregation must succeed: {}", error), }; assert_eq!(first_results.len(), 1); assert!(first_results[0].created_trade_event); - let second_result = service - .record_transaction_by_signature("sig-trade-aggregation-2") - .await; + let second_result = + service.record_transaction_by_signature("sig-trade-aggregation-2").await; let second_results = match second_result { Ok(second_results) => second_results, Err(error) => panic!("second trade aggregation must succeed: {}", error), diff --git a/kb_lib/src/tx_model.rs b/kb_lib/src/tx_model.rs index ca793e3..73664de 100644 --- a/kb_lib/src/tx_model.rs +++ b/kb_lib/src/tx_model.rs @@ -11,7 +11,7 @@ pub struct KbTransactionModelService { impl KbTransactionModelService { /// Creates one transaction model projection service. pub fn new(database: std::sync::Arc) -> Self { - Self { database } + return Self { database }; } /// Projects one resolved transaction JSON into slots / transactions / instructions tables. @@ -21,9 +21,7 @@ impl KbTransactionModelService { source_endpoint_name: std::option::Option, resolved_transaction: &serde_json::Value, ) -> Result { - let slot_i64 = resolved_transaction - .get("slot") - .and_then(serde_json::Value::as_i64); + let slot_i64 = resolved_transaction.get("slot").and_then(serde_json::Value::as_i64); let slot_u64 = match slot_i64 { Some(slot_i64) => { let convert_result = u64::try_from(slot_i64); @@ -34,14 +32,13 @@ impl KbTransactionModelService { "cannot convert resolved transaction slot '{}' to u64: {}", slot_i64, error ))); - } + }, } - } + }, None => None, }; - let block_time_unix = resolved_transaction - .get("blockTime") - .and_then(serde_json::Value::as_i64); + let block_time_unix = + resolved_transaction.get("blockTime").and_then(serde_json::Value::as_i64); if let Some(slot_value) = slot_u64 { let slot_dto = crate::KbChainSlotDto::new(slot_value, None, block_time_unix); let upsert_result = crate::upsert_chain_slot(self.database.as_ref(), &slot_dto).await; @@ -60,7 +57,7 @@ impl KbTransactionModelService { "cannot serialize resolved transaction '{}': {}", signature, error ))); - } + }, }; let transaction_dto = crate::KbChainTransactionDto::new( signature.to_string(), @@ -97,7 +94,7 @@ impl KbTransactionModelService { "cannot convert outer instruction index '{}' to u32: {}", index, error ))); - } + }, }; let dto_result = kb_build_instruction_dto( transaction_id, @@ -138,7 +135,7 @@ impl KbTransactionModelService { "cannot convert inner instruction index '{}' to u32: {}", inner_index, error ))); - } + }, }; let dto_result = kb_build_instruction_dto( transaction_id, @@ -158,7 +155,7 @@ impl KbTransactionModelService { } } } - Ok(transaction_id) + return Ok(transaction_id); } } @@ -182,8 +179,7 @@ fn kb_extract_version_text( if let Some(version_number) = version_value.as_i64() { return Some(version_number.to_string()); } - - None + return None; } fn kb_extract_meta_json( @@ -196,8 +192,8 @@ fn kb_extract_meta_json( }; let serialize_result = serde_json::to_string(meta); match serialize_result { - Ok(json_text) => Some(json_text), - Err(_) => None, + Ok(json_text) => return Some(json_text), + Err(_) => return None, } } @@ -219,8 +215,8 @@ fn kb_extract_meta_err_json( } let serialize_result = serde_json::to_string(err); match serialize_result { - Ok(json_text) => Some(json_text), - Err(_) => None, + Ok(json_text) => return Some(json_text), + Err(_) => return None, } } @@ -251,7 +247,7 @@ fn kb_extract_outer_instructions( for instruction in array { instructions.push(instruction.clone()); } - instructions + return instructions; } fn kb_extract_inner_instruction_groups( @@ -282,7 +278,7 @@ fn kb_extract_inner_instruction_groups( Ok(index_u32) => Some(index_u32), Err(_) => None, } - } + }, None => None, }; let mut instructions = std::vec::Vec::new(); @@ -294,12 +290,9 @@ fn kb_extract_inner_instruction_groups( } } } - groups.push(KbInnerInstructionGroup { - index, - instructions, - }); + groups.push(KbInnerInstructionGroup { index, instructions }); } - groups + return groups; } fn kb_build_instruction_dto( @@ -317,10 +310,7 @@ fn kb_build_instruction_dto( .get("program") .and_then(serde_json::Value::as_str) .map(std::string::ToString::to_string); - let stack_height = match instruction - .get("stackHeight") - .and_then(serde_json::Value::as_i64) - { + let stack_height = match instruction.get("stackHeight").and_then(serde_json::Value::as_i64) { Some(stack_height_i64) => { let stack_height_result = u32::try_from(stack_height_i64); match stack_height_result { @@ -330,9 +320,9 @@ fn kb_build_instruction_dto( "cannot convert instruction stack_height '{}' to u32: {}", stack_height_i64, error ))); - } + }, } - } + }, None => None, }; let accounts_json = if let Some(accounts) = instruction.get("accounts") { @@ -344,7 +334,7 @@ fn kb_build_instruction_dto( "cannot serialize instruction accounts json: {}", error ))); - } + }, } } else { "[]".to_string() @@ -359,14 +349,14 @@ fn kb_build_instruction_dto( "cannot serialize instruction data json: {}", error ))); - } + }, } - } + }, None => None, }; let parsed_type = instruction .get("parsed") - .and_then(|parsed| parsed.get("type")) + .and_then(|parsed| return parsed.get("type")) .and_then(serde_json::Value::as_str) .map(std::string::ToString::to_string); let parsed_json = match instruction.get("parsed") { @@ -379,12 +369,12 @@ fn kb_build_instruction_dto( "cannot serialize instruction parsed json: {}", error ))); - } + }, } - } + }, None => None, }; - Ok(crate::KbChainInstructionDto::new( + return Ok(crate::KbChainInstructionDto::new( transaction_id, parent_instruction_id, instruction_index, @@ -396,7 +386,7 @@ fn kb_build_instruction_dto( data_json, parsed_type, parsed_json, - )) + )); } #[cfg(test)] @@ -419,7 +409,7 @@ mod tests { let database = crate::KbDatabase::connect_and_initialize(&config) .await .expect("database init must succeed"); - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } #[tokio::test] @@ -481,10 +471,7 @@ mod tests { .expect("chain transaction must exist"); assert_eq!(transaction.id, Some(transaction_id)); assert_eq!(transaction.slot, Some(700001)); - assert_eq!( - transaction.source_endpoint_name, - Some("helius_primary_http".to_string()) - ); + assert_eq!(transaction.source_endpoint_name, Some("helius_primary_http".to_string())); assert_eq!(transaction.version_text, Some("0".to_string())); let instructions = crate::list_chain_instructions_by_transaction_id(database.as_ref(), transaction_id) @@ -677,14 +664,8 @@ mod tests { .expect("second chain instructions list must succeed"); assert_eq!(second_instructions.len(), 1); assert_eq!(second_instructions[0].instruction_index, 0); - assert_eq!( - second_instructions[0].program_name, - Some("only-program".to_string()) - ); - assert_eq!( - second_instructions[0].parsed_type, - Some("singleInstruction".to_string()) - ); + assert_eq!(second_instructions[0].program_name, Some("only-program".to_string())); + assert_eq!(second_instructions[0].parsed_type, Some("singleInstruction".to_string())); let transaction = crate::get_chain_transaction_by_signature(database.as_ref(), "sig-model-replace-1") .await diff --git a/kb_lib/src/tx_resolution.rs b/kb_lib/src/tx_resolution.rs index 80795e8..76836ff 100644 --- a/kb_lib/src/tx_resolution.rs +++ b/kb_lib/src/tx_resolution.rs @@ -38,11 +38,11 @@ impl KbWsTransactionResolutionEnvelope { notification: crate::KbJsonRpcWsNotification, subscription: std::option::Option, ) -> Self { - Self { + return Self { endpoint_name, notification, subscription, - } + }; } } @@ -134,7 +134,7 @@ impl KbTransactionResolutionService { crate::KbPairCandleAggregationService::new(database.clone()); let pair_analytic_signal_service = crate::KbPairAnalyticSignalService::new(database.clone()); - Self { + return Self { http_pool, persistence, http_role, @@ -151,12 +151,12 @@ impl KbTransactionResolutionService { resolved_signatures: std::sync::Arc::new(tokio::sync::Mutex::new( std::collections::HashSet::new(), )), - } + }; } /// Returns the persistence façade used by the resolver. pub fn persistence(&self) -> &crate::KbDetectionPersistenceService { - &self.persistence + return &self.persistence; } /// Builds one transaction resolution request from one WS envelope. @@ -178,7 +178,7 @@ impl KbTransactionResolutionService { None => return None, }; let slot_hint = kb_extract_resolution_slot(&envelope.notification); - Some(crate::KbTransactionResolutionRequest { + return Some(crate::KbTransactionResolutionRequest { signature, trigger_method: envelope.notification.method.clone(), source_endpoint_name: envelope.endpoint_name.clone(), @@ -189,7 +189,7 @@ impl KbTransactionResolutionService { "subscription": envelope.notification.params.subscription, "result": envelope.notification.params.result, }), - }) + }); } /// Processes one forwarded WS envelope. @@ -221,21 +221,21 @@ impl KbTransactionResolutionService { signature: request.signature.clone(), signal_id, }); - } + }, }; match &outcome { crate::KbTransactionResolutionOutcome::Resolved { signature, .. } => { let mut resolved_guard = self.resolved_signatures.lock().await; resolved_guard.insert(signature.clone()); - } + }, crate::KbTransactionResolutionOutcome::Missing { signature, .. } => { let mut resolved_guard = self.resolved_signatures.lock().await; resolved_guard.insert(signature.clone()); - } - crate::KbTransactionResolutionOutcome::Ignored => {} - crate::KbTransactionResolutionOutcome::ErrorSignaled { .. } => {} + }, + crate::KbTransactionResolutionOutcome::Ignored => {}, + crate::KbTransactionResolutionOutcome::ErrorSignaled { .. } => {}, } - Ok(outcome) + return Ok(outcome); } async fn resolve_request( @@ -450,11 +450,11 @@ impl KbTransactionResolutionService { Ok(signal_id) => signal_id, Err(error) => return Err(error), }; - Ok(crate::KbTransactionResolutionOutcome::Resolved { + return Ok(crate::KbTransactionResolutionOutcome::Resolved { signature: request.signature.clone(), observation_id, signal_id, - }) + }); } async fn record_resolution_error_signal( @@ -471,7 +471,8 @@ impl KbTransactionResolutionService { "triggerPayload": request.trigger_payload.clone(), "error": error.to_string() }); - self.persistence + return self + .persistence .record_signal(&crate::KbDetectionSignalInput::new( "signal.transaction_resolution.error".to_string(), crate::KbAnalysisSignalSeverity::High, @@ -480,7 +481,7 @@ impl KbTransactionResolutionService { None, payload, )) - .await + .await; } } @@ -494,7 +495,7 @@ pub struct KbWsTransactionResolutionRelay { impl KbWsTransactionResolutionRelay { /// Creates a new transaction resolution relay. pub fn new(resolver: crate::KbTransactionResolutionService) -> Self { - Self { resolver } + return Self { resolver }; } /// Creates a bounded relay channel. @@ -504,7 +505,7 @@ impl KbWsTransactionResolutionRelay { tokio::sync::mpsc::Sender, tokio::sync::mpsc::Receiver, ) { - tokio::sync::mpsc::channel(capacity) + return tokio::sync::mpsc::channel(capacity); } /// Processes one forwarded envelope. @@ -512,7 +513,7 @@ impl KbWsTransactionResolutionRelay { &self, envelope: &crate::KbWsTransactionResolutionEnvelope, ) -> Result { - self.resolver.process_ws_envelope(envelope).await + return self.resolver.process_ws_envelope(envelope).await; } /// Spawns one background relay worker. @@ -520,7 +521,7 @@ impl KbWsTransactionResolutionRelay { self, mut receiver: tokio::sync::mpsc::Receiver, ) -> tokio::task::JoinHandle { - tokio::spawn(async move { + return tokio::spawn(async move { let mut stats = crate::KbWsTransactionResolutionRelayStats::default(); loop { let recv_result = receiver.recv().await; @@ -541,25 +542,25 @@ impl KbWsTransactionResolutionRelay { error ); continue; - } + }, }; match outcome { crate::KbTransactionResolutionOutcome::Ignored => { stats.ignored_count += 1; - } + }, crate::KbTransactionResolutionOutcome::Resolved { .. } => { stats.resolved_count += 1; - } + }, crate::KbTransactionResolutionOutcome::Missing { .. } => { stats.missing_count += 1; - } + }, crate::KbTransactionResolutionOutcome::ErrorSignaled { .. } => { stats.error_count += 1; - } + }, } } - stats - }) + return stats; + }); } } @@ -585,7 +586,7 @@ fn kb_extract_resolution_signature( } } } - None + return None; } fn kb_extract_resolution_slot( @@ -605,5 +606,5 @@ fn kb_extract_resolution_slot( return Some(slot); } } - None + return None; } diff --git a/kb_lib/src/wallet_holding_observation.rs b/kb_lib/src/wallet_holding_observation.rs index 875ee6d..5707464 100644 --- a/kb_lib/src/wallet_holding_observation.rs +++ b/kb_lib/src/wallet_holding_observation.rs @@ -26,10 +26,7 @@ impl KbWalletHoldingObservationService { /// Creates a new wallet-holding observation service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Records observed wallet holdings for one resolved transaction signature. @@ -50,7 +47,7 @@ impl KbWalletHoldingObservationService { "cannot record wallet holdings for unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { Some(transaction_id) => transaction_id, @@ -59,7 +56,7 @@ impl KbWalletHoldingObservationService { "transaction '{}' has no internal id", signature ))); - } + }, }; let decoded_events_result = crate::list_dex_decoded_events_by_transaction_id( self.database.as_ref(), @@ -80,7 +77,7 @@ impl KbWalletHoldingObservationService { return Err(crate::KbError::InvalidState( "decoded event has no internal id".to_string(), )); - } + }, }; let pool_id = match decoded_event.pool_account.clone() { Some(pool_address) => { @@ -95,7 +92,7 @@ impl KbWalletHoldingObservationService { Some(pool) => pool.id, None => None, } - } + }, None => None, }; let pair_id = match pool_id { @@ -110,7 +107,7 @@ impl KbWalletHoldingObservationService { Some(pair) => pair.id, None => None, } - } + }, None => None, }; let payload_result = @@ -122,7 +119,7 @@ impl KbWalletHoldingObservationService { "cannot parse decoded_event payload_json '{}': {}", decoded_event.payload_json, error ))); - } + }, }; let wallet_roles = kb_collect_wallet_roles(&payload); let token_mints = kb_collect_token_mints(decoded_event); @@ -144,7 +141,7 @@ impl KbWalletHoldingObservationService { return Err(crate::KbError::InvalidState( "wallet has no internal id".to_string(), )); - } + }, }; for token_mint in &token_mints { let token_result = @@ -163,7 +160,7 @@ impl KbWalletHoldingObservationService { return Err(crate::KbError::InvalidState( "token has no internal id".to_string(), )); - } + }, }; let dedupe_key = (wallet_id, token_id, Some(decoded_event_id)); if seen_pairs.contains(&dedupe_key) { @@ -254,7 +251,7 @@ impl KbWalletHoldingObservationService { } } } - Ok(results) + return Ok(results); } } @@ -280,7 +277,7 @@ fn kb_collect_wallet_roles( results.push((role.to_string(), address)); } } - results + return results; } fn kb_collect_token_mints( @@ -300,8 +297,7 @@ fn kb_collect_token_mints( values.push(token_b_mint); } } - - values + return values; } fn kb_extract_strings_for_candidate_keys( @@ -310,7 +306,7 @@ fn kb_extract_strings_for_candidate_keys( ) -> std::vec::Vec { let mut values = std::vec::Vec::new(); kb_extract_strings_for_candidate_keys_inner(value, candidate_keys, &mut values); - values + return values; } fn kb_extract_strings_for_candidate_keys_inner( @@ -343,10 +339,10 @@ fn kb_extract_strings_for_candidate_keys_inner( fn kb_convert_slot_to_i64(slot: std::option::Option) -> std::option::Option { match slot { Some(slot) => match i64::try_from(slot) { - Ok(slot) => Some(slot), - Err(_) => None, + Ok(slot) => return Some(slot), + Err(_) => return None, }, - None => None, + None => return None, } } @@ -376,7 +372,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fluxbeam_create_transaction( @@ -445,9 +441,7 @@ mod tests { if let Err(error) = detect_result { panic!("dex detect must succeed: {}", error); } - let wallet_result = wallet_observation - .record_transaction_by_signature(signature) - .await; + let wallet_result = wallet_observation.record_transaction_by_signature(signature).await; if let Err(error) = wallet_result { panic!("wallet observation must succeed: {}", error); } @@ -458,9 +452,7 @@ mod tests { let database = make_database().await; seed_fluxbeam_create_transaction(database.clone(), "sig-wallet-holding-1").await; let service = crate::KbWalletHoldingObservationService::new(database.clone()); - let record_result = service - .record_transaction_by_signature("sig-wallet-holding-1") - .await; + let record_result = service.record_transaction_by_signature("sig-wallet-holding-1").await; let results = match record_result { Ok(results) => results, Err(error) => panic!("wallet holding observation must succeed: {}", error), @@ -501,9 +493,7 @@ mod tests { let database = make_database().await; seed_fluxbeam_create_transaction(database.clone(), "sig-wallet-holding-2").await; let service = crate::KbWalletHoldingObservationService::new(database.clone()); - let first_result = service - .record_transaction_by_signature("sig-wallet-holding-2") - .await; + let first_result = service.record_transaction_by_signature("sig-wallet-holding-2").await; let first_results = match first_result { Ok(first_results) => first_results, Err(error) => panic!("first wallet holding observation must succeed: {}", error), @@ -511,9 +501,7 @@ mod tests { assert_eq!(first_results.len(), 2); assert!(first_results[0].created_holding); assert!(first_results[1].created_holding); - let second_result = service - .record_transaction_by_signature("sig-wallet-holding-2") - .await; + let second_result = service.record_transaction_by_signature("sig-wallet-holding-2").await; let second_results = match second_result { Ok(second_results) => second_results, Err(error) => panic!("second wallet holding observation must succeed: {}", error), diff --git a/kb_lib/src/wallet_observation.rs b/kb_lib/src/wallet_observation.rs index 76fcf10..13c7cd6 100644 --- a/kb_lib/src/wallet_observation.rs +++ b/kb_lib/src/wallet_observation.rs @@ -32,10 +32,7 @@ impl KbWalletObservationService { /// Creates a new wallet-observation service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { - database, - persistence, - } + return Self { database, persistence }; } /// Records observed wallets and participations for one resolved transaction signature. @@ -56,7 +53,7 @@ impl KbWalletObservationService { "cannot record wallet observations for unknown transaction '{}'", signature ))); - } + }, }; let transaction_id = match transaction.id { Some(transaction_id) => transaction_id, @@ -65,7 +62,7 @@ impl KbWalletObservationService { "transaction '{}' has no internal id", signature ))); - } + }, }; let decoded_events_result = crate::list_dex_decoded_events_by_transaction_id( self.database.as_ref(), @@ -84,7 +81,7 @@ impl KbWalletObservationService { return Err(crate::KbError::InvalidState( "decoded event has no internal id".to_string(), )); - } + }, }; let pool_id = match decoded_event.pool_account.clone() { Some(pool_address) => { @@ -99,7 +96,7 @@ impl KbWalletObservationService { Some(pool) => pool.id, None => None, } - } + }, None => None, }; let pair_id = match pool_id { @@ -114,7 +111,7 @@ impl KbWalletObservationService { Some(pair) => pair.id, None => None, } - } + }, None => None, }; let payload_result = @@ -126,7 +123,7 @@ impl KbWalletObservationService { "cannot parse decoded_event payload_json '{}': {}", decoded_event.payload_json, error ))); - } + }, }; let observed_roles = kb_collect_wallet_roles(&payload); for (role, wallet_address) in observed_roles { @@ -150,12 +147,12 @@ impl KbWalletObservationService { Ok(_) => wallet_id, Err(error) => return Err(error), } - } + }, None => { return Err(crate::KbError::InvalidState( "wallet has no internal id".to_string(), )); - } + }, }, None => { let dto = crate::KbWalletDto::new(wallet_address.clone(), None); @@ -165,7 +162,7 @@ impl KbWalletObservationService { Ok(wallet_id) => wallet_id, Err(error) => return Err(error), } - } + }, }; let participation_dto = crate::KbWalletParticipationDto::new( wallet_id, @@ -245,7 +242,7 @@ impl KbWalletObservationService { }); } } - Ok(results) + return Ok(results); } } @@ -271,7 +268,7 @@ fn kb_collect_wallet_roles( results.push((role.to_string(), address)); } } - results + return results; } fn kb_extract_strings_for_candidate_keys( @@ -280,7 +277,7 @@ fn kb_extract_strings_for_candidate_keys( ) -> std::vec::Vec { let mut values = std::vec::Vec::new(); kb_extract_strings_for_candidate_keys_inner(value, candidate_keys, &mut values); - values + return values; } fn kb_extract_strings_for_candidate_keys_inner( @@ -336,7 +333,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_fluxbeam_transaction( @@ -411,9 +408,8 @@ mod tests { let database = make_database().await; seed_fluxbeam_transaction(database.clone(), "sig-wallet-observation-1").await; let service = crate::KbWalletObservationService::new(database.clone()); - let record_result = service - .record_transaction_by_signature("sig-wallet-observation-1") - .await; + let record_result = + service.record_transaction_by_signature("sig-wallet-observation-1").await; let results = match record_result { Ok(results) => results, Err(error) => panic!("wallet observation must succeed: {}", error), @@ -450,9 +446,8 @@ mod tests { let database = make_database().await; seed_fluxbeam_transaction(database.clone(), "sig-wallet-observation-2").await; let service = crate::KbWalletObservationService::new(database.clone()); - let first_result = service - .record_transaction_by_signature("sig-wallet-observation-2") - .await; + let first_result = + service.record_transaction_by_signature("sig-wallet-observation-2").await; let first_results = match first_result { Ok(first_results) => first_results, Err(error) => panic!("first wallet observation must succeed: {}", error), @@ -460,9 +455,8 @@ mod tests { assert_eq!(first_results.len(), 2); assert!(first_results[0].created_participation); assert!(first_results[1].created_participation); - let second_result = service - .record_transaction_by_signature("sig-wallet-observation-2") - .await; + let second_result = + service.record_transaction_by_signature("sig-wallet-observation-2").await; let second_results = match second_result { Ok(second_results) => second_results, Err(error) => panic!("second wallet observation must succeed: {}", error), diff --git a/kb_lib/src/ws_client.rs b/kb_lib/src/ws_client.rs index 654b3c3..e505d97 100644 --- a/kb_lib/src/ws_client.rs +++ b/kb_lib/src/ws_client.rs @@ -170,7 +170,7 @@ struct WsClientRuntime { impl WsClientRuntime { fn new() -> Self { - Self { + return Self { generation: 0, writer_tx: None, shutdown_tx: None, @@ -178,7 +178,7 @@ impl WsClientRuntime { read_abort_handle: None, write_abort_handle: None, supervisor_abort_handle: None, - } + }; } } @@ -190,10 +190,10 @@ struct WsClientRegistry { impl WsClientRegistry { fn new() -> Self { - Self { + return Self { pending_requests: std::collections::BTreeMap::new(), active_subscriptions: std::collections::BTreeMap::new(), - } + }; } } @@ -263,7 +263,7 @@ impl WsClient { Err(error) => return Err(error), }; let (event_tx, _) = tokio::sync::broadcast::channel(endpoint.event_channel_capacity); - Ok(Self { + return Ok(Self { endpoint, resolved_url, next_request_id: std::sync::Arc::new(std::sync::atomic::AtomicU64::new(1)), @@ -277,27 +277,27 @@ impl WsClient { transaction_resolution_notification_forwarder: std::sync::Arc::new( tokio::sync::Mutex::new(None), ), - }) + }); } /// Returns the endpoint name of this client. pub fn endpoint_name(&self) -> &str { - &self.endpoint.name + return &self.endpoint.name; } /// Returns the resolved endpoint URL of this client. pub fn endpoint_url(&self) -> &str { - &self.resolved_url + return &self.resolved_url; } /// Returns the endpoint configuration of this client. pub fn endpoint_config(&self) -> &crate::KbWsEndpointConfig { - &self.endpoint + return &self.endpoint; } /// Returns a new broadcast receiver subscribed to transport events. pub fn subscribe_events(&self) -> tokio::sync::broadcast::Receiver { - self.event_tx.subscribe() + return self.event_tx.subscribe(); } /// Sets the optional detection notification forwarder. @@ -317,36 +317,31 @@ impl WsClient { /// Returns the next request identifier and increments the internal counter. pub fn next_request_id(&self) -> u64 { - self.next_request_id - .fetch_add(1, std::sync::atomic::Ordering::Relaxed) + return self.next_request_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } /// Returns the current connection state. pub async fn connection_state(&self) -> crate::KbConnectionState { let state_guard = self.state.read().await; - *state_guard + return *state_guard; } /// Returns the number of tracked pending JSON-RPC requests. pub async fn pending_request_count(&self) -> usize { let registry_guard = self.registry.lock().await; - registry_guard.pending_requests.len() + return registry_guard.pending_requests.len(); } /// Returns the number of tracked active subscriptions. pub async fn active_subscription_count(&self) -> usize { let registry_guard = self.registry.lock().await; - registry_guard.active_subscriptions.len() + return registry_guard.active_subscriptions.len(); } /// Returns a snapshot of the tracked active subscriptions. pub async fn active_subscriptions(&self) -> std::vec::Vec { let registry_guard = self.registry.lock().await; - registry_guard - .active_subscriptions - .values() - .cloned() - .collect() + return registry_guard.active_subscriptions.values().cloned().collect(); } /// Connects the client to its remote WebSocket endpoint. @@ -390,7 +385,7 @@ impl WsClient { let mut state_guard = self.state.write().await; *state_guard = crate::KbConnectionState::Disconnected; return Err(error); - } + }, }; let (ws_stream, _response) = match connect_result { Ok(parts) => parts, @@ -406,7 +401,7 @@ impl WsClient { let mut state_guard = self.state.write().await; *state_guard = crate::KbConnectionState::Disconnected; return Err(kb_error); - } + }, }; let (write_half, read_half) = ws_stream.split(); let (writer_tx, writer_rx) = @@ -421,9 +416,7 @@ impl WsClient { let read_abort_handle = read_handle.abort_handle(); let write_client = self.clone(); let write_handle = tokio::spawn(async move { - write_client - .run_write_loop(write_half, writer_rx, shutdown_rx) - .await; + write_client.run_write_loop(write_half, writer_rx, shutdown_rx).await; }); let write_abort_handle = write_handle.abort_handle(); let generation = { @@ -471,7 +464,7 @@ impl WsClient { endpoint_url = %self.resolved_url, "websocket client connected" ); - Ok(()) + return Ok(()); } /// Sends a transport-level WebSocket message. @@ -487,44 +480,48 @@ impl WsClient { "ws client '{}' is not connected", self.endpoint.name ))); - } + }, }; let queue_timeout = std::time::Duration::from_millis(self.endpoint.request_timeout_ms); let send_future = writer_tx.send(WsWriteCommand::Send(message)); let timeout_result = tokio::time::timeout(queue_timeout, send_future).await; match timeout_result { Ok(send_result) => match send_result { - Ok(()) => Ok(()), - Err(error) => Err(crate::KbError::Ws(format!( - "cannot queue outgoing websocket message for endpoint '{}': {error}", - self.endpoint.name - ))), + Ok(()) => return Ok(()), + Err(error) => { + return Err(crate::KbError::Ws(format!( + "cannot queue outgoing websocket message for endpoint '{}': {error}", + self.endpoint.name + ))); + }, + }, + Err(_) => { + return Err(crate::KbError::Ws(format!( + "timeout while queueing outgoing websocket message for endpoint '{}'", + self.endpoint.name + ))); }, - Err(_) => Err(crate::KbError::Ws(format!( - "timeout while queueing outgoing websocket message for endpoint '{}'", - self.endpoint.name - ))), } } /// Sends a UTF-8 text message. pub async fn send_text(&self, text: std::string::String) -> Result<(), crate::KbError> { - self.send_message(WsOutgoingMessage::Text(text)).await + return self.send_message(WsOutgoingMessage::Text(text)).await; } /// Sends a binary message. pub async fn send_binary(&self, data: std::vec::Vec) -> Result<(), crate::KbError> { - self.send_message(WsOutgoingMessage::Binary(data)).await + return self.send_message(WsOutgoingMessage::Binary(data)).await; } /// Sends a ping message. pub async fn send_ping(&self, data: std::vec::Vec) -> Result<(), crate::KbError> { - self.send_message(WsOutgoingMessage::Ping(data)).await + return self.send_message(WsOutgoingMessage::Ping(data)).await; } /// Sends a pong message. pub async fn send_pong(&self, data: std::vec::Vec) -> Result<(), crate::KbError> { - self.send_message(WsOutgoingMessage::Pong(data)).await + return self.send_message(WsOutgoingMessage::Pong(data)).await; } /// Serializes and sends a JSON value as a text message. @@ -537,9 +534,9 @@ impl WsClient { "cannot serialize websocket json payload for endpoint '{}': {error}", self.endpoint.name ))); - } + }, }; - self.send_text(text).await + return self.send_text(text).await; } /// Sends a prebuilt JSON-RPC request object and tracks it when the request id is numeric. @@ -563,13 +560,11 @@ impl WsClient { if let Err(error) = send_result { if let Some(tracked_request) = tracked_request { let mut registry_guard = self.registry.lock().await; - registry_guard - .pending_requests - .remove(&tracked_request.request_id); + registry_guard.pending_requests.remove(&tracked_request.request_id); } return Err(error); } - Ok(()) + return Ok(()); } /// Builds and sends a JSON-RPC request with a generated numeric identifier. @@ -584,8 +579,8 @@ impl WsClient { let request = crate::KbJsonRpcWsRequest::new_with_u64_id(request_id, method, params); let send_result = self.send_json_rpc_request_object(&request).await; match send_result { - Ok(()) => Ok(request_id), - Err(error) => Err(error), + Ok(()) => return Ok(request_id), + Err(error) => return Err(error), } } @@ -596,8 +591,7 @@ impl WsClient { config: std::option::Option, ) -> Result { let params = kb_build_single_key_optional_config_params(pubkey, config); - self.send_json_rpc_request("accountSubscribe".to_string(), params) - .await + return self.send_json_rpc_request("accountSubscribe".to_string(), params).await; } /// Unsubscribes from an account change subscription using raw JSON values. @@ -605,11 +599,12 @@ impl WsClient { &self, subscription_id: u64, ) -> Result { - self.send_json_rpc_request( - "accountUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "accountUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to block notifications using raw JSON values. @@ -621,17 +616,17 @@ impl WsClient { config: std::option::Option, ) -> Result { let params = kb_build_first_value_optional_config_params(filter, config); - self.send_json_rpc_request("blockSubscribe".to_string(), params) - .await + return self.send_json_rpc_request("blockSubscribe".to_string(), params).await; } /// Unsubscribes from a block notification subscription using raw JSON values. pub async fn block_unsubscribe_raw(&self, subscription_id: u64) -> Result { - self.send_json_rpc_request( - "blockUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "blockUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to transaction log notifications using raw JSON values. @@ -641,17 +636,17 @@ impl WsClient { config: std::option::Option, ) -> Result { let params = kb_build_first_value_optional_config_params(filter, config); - self.send_json_rpc_request("logsSubscribe".to_string(), params) - .await + return self.send_json_rpc_request("logsSubscribe".to_string(), params).await; } /// Unsubscribes from a logs subscription using raw JSON values. pub async fn logs_unsubscribe_raw(&self, subscription_id: u64) -> Result { - self.send_json_rpc_request( - "logsUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "logsUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to program-owned account notifications using raw JSON values. @@ -661,8 +656,7 @@ impl WsClient { config: std::option::Option, ) -> Result { let params = kb_build_single_key_optional_config_params(program_id, config); - self.send_json_rpc_request("programSubscribe".to_string(), params) - .await + return self.send_json_rpc_request("programSubscribe".to_string(), params).await; } /// Unsubscribes from a program subscription using raw JSON values. @@ -670,26 +664,29 @@ impl WsClient { &self, subscription_id: u64, ) -> Result { - self.send_json_rpc_request( - "programUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "programUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to root notifications. pub async fn root_subscribe(&self) -> Result { - self.send_json_rpc_request("rootSubscribe".to_string(), std::vec::Vec::new()) - .await + return self + .send_json_rpc_request("rootSubscribe".to_string(), std::vec::Vec::new()) + .await; } /// Unsubscribes from a root subscription. pub async fn root_unsubscribe(&self, subscription_id: u64) -> Result { - self.send_json_rpc_request( - "rootUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "rootUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to one transaction signature status using raw JSON values. @@ -699,8 +696,7 @@ impl WsClient { config: std::option::Option, ) -> Result { let params = kb_build_single_key_optional_config_params(signature, config); - self.send_json_rpc_request("signatureSubscribe".to_string(), params) - .await + return self.send_json_rpc_request("signatureSubscribe".to_string(), params).await; } /// Unsubscribes from a signature subscription using raw JSON values. @@ -708,32 +704,36 @@ impl WsClient { &self, subscription_id: u64, ) -> Result { - self.send_json_rpc_request( - "signatureUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "signatureUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to slot notifications. pub async fn slot_subscribe(&self) -> Result { - self.send_json_rpc_request("slotSubscribe".to_string(), std::vec::Vec::new()) - .await + return self + .send_json_rpc_request("slotSubscribe".to_string(), std::vec::Vec::new()) + .await; } /// Unsubscribes from a slot subscription. pub async fn slot_unsubscribe(&self, subscription_id: u64) -> Result { - self.send_json_rpc_request( - "slotUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "slotUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to slot lifecycle update notifications. pub async fn slots_updates_subscribe(&self) -> Result { - self.send_json_rpc_request("slotsUpdatesSubscribe".to_string(), std::vec::Vec::new()) - .await + return self + .send_json_rpc_request("slotsUpdatesSubscribe".to_string(), std::vec::Vec::new()) + .await; } /// Unsubscribes from a slot lifecycle update subscription. @@ -741,31 +741,34 @@ impl WsClient { &self, subscription_id: u64, ) -> Result { - self.send_json_rpc_request( - "slotsUpdatesUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "slotsUpdatesUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Subscribes to vote notifications. pub async fn vote_subscribe(&self) -> Result { - self.send_json_rpc_request("voteSubscribe".to_string(), std::vec::Vec::new()) - .await + return self + .send_json_rpc_request("voteSubscribe".to_string(), std::vec::Vec::new()) + .await; } /// Unsubscribes from a vote subscription. pub async fn vote_unsubscribe(&self, subscription_id: u64) -> Result { - self.send_json_rpc_request( - "voteUnsubscribe".to_string(), - vec![serde_json::Value::from(subscription_id)], - ) - .await + return self + .send_json_rpc_request( + "voteUnsubscribe".to_string(), + vec![serde_json::Value::from(subscription_id)], + ) + .await; } /// Initiates the close handshake. pub async fn send_close(&self) -> Result<(), crate::KbError> { - self.send_message(WsOutgoingMessage::Close).await + return self.send_message(WsOutgoingMessage::Close).await; } /// Disconnects the client from its remote endpoint. @@ -833,13 +836,13 @@ impl WsClient { "cannot queue close frame during disconnect: {error}" ); } - } + }, Err(_) => { tracing::warn!( endpoint_name = %self.endpoint.name, "timeout while queueing close frame during disconnect" ); - } + }, } } if let Some(shutdown_tx) = shutdown_tx_option { @@ -861,13 +864,13 @@ impl WsClient { }); } return Ok(()); - } + }, }; let completion_timeout = std::time::Duration::from_millis(self.endpoint.request_timeout_ms); let notified_future = completion_notify.notified(); let completion_result = tokio::time::timeout(completion_timeout, notified_future).await; match completion_result { - Ok(()) => Ok(()), + Ok(()) => return Ok(()), Err(_) => { tracing::warn!( endpoint_name = %self.endpoint.name, @@ -888,8 +891,8 @@ impl WsClient { endpoint_name: self.endpoint.name.clone(), }); } - Ok(()) - } + return Ok(()); + }, } } @@ -935,7 +938,7 @@ impl WsClient { } tokio::time::sleep(std::time::Duration::from_millis(25)).await; } - Ok(subscriptions.len()) + return Ok(subscriptions.len()); } async fn run_supervisor( @@ -990,7 +993,7 @@ impl WsClient { None => { let _ = shutdown_tx.send(true); break; - } + }, }; let message = match message_result { Ok(message) => message, @@ -1006,7 +1009,7 @@ impl WsClient { } let _ = shutdown_tx.send(true); break; - } + }, }; match message { tokio_tungstenite::tungstenite::Message::Text(text) => { @@ -1024,35 +1027,35 @@ impl WsClient { message: parsed_message.clone(), }); self.handle_incoming_json_rpc_message(&parsed_message).await; - } + }, Err(error) => { self.emit_event(WsEvent::JsonRpcParseError { endpoint_name: self.endpoint.name.clone(), text: text_string.clone(), error, }); - } + }, } } - } + }, tokio_tungstenite::tungstenite::Message::Binary(data) => { self.emit_event(WsEvent::BinaryMessage { endpoint_name: self.endpoint.name.clone(), data: data.to_vec(), }); - } + }, tokio_tungstenite::tungstenite::Message::Ping(data) => { self.emit_event(WsEvent::Ping { endpoint_name: self.endpoint.name.clone(), data: data.to_vec(), }); - } + }, tokio_tungstenite::tungstenite::Message::Pong(data) => { self.emit_event(WsEvent::Pong { endpoint_name: self.endpoint.name.clone(), data: data.to_vec(), }); - } + }, tokio_tungstenite::tungstenite::Message::Close(frame_option) => { let mut code_option = None; let mut reason_option = None; @@ -1070,13 +1073,13 @@ impl WsClient { }); let _ = shutdown_tx.send(true); break; - } + }, tokio_tungstenite::tungstenite::Message::Frame(_frame) => { tracing::trace!( endpoint_name = %self.endpoint.name, "ignoring internal tungstenite frame variant" ); - } + }, } } } @@ -1098,7 +1101,7 @@ impl WsClient { None => return, }; match pending_request.kind { - WsPendingJsonRpcRequestKind::Generic => {} + WsPendingJsonRpcRequestKind::Generic => {}, WsPendingJsonRpcRequestKind::Subscribe { notification_method, unsubscribe_method, @@ -1127,7 +1130,7 @@ impl WsClient { endpoint_name: self.endpoint.name.clone(), subscription, }); - } + }, WsPendingJsonRpcRequestKind::Unsubscribe { subscription_id, unsubscribe_method, @@ -1146,9 +1149,9 @@ impl WsClient { unsubscribe_method, was_active: removed_subscription_option.is_some(), }); - } + }, } - } + }, crate::KbJsonRpcWsIncomingMessage::ErrorResponse(response) => { let request_id_option = kb_json_value_to_u64(&response.id); let request_id = match request_id_option { @@ -1157,15 +1160,12 @@ impl WsClient { }; let mut registry_guard = self.registry.lock().await; registry_guard.pending_requests.remove(&request_id); - } + }, crate::KbJsonRpcWsIncomingMessage::Notification(notification) => { let subscription_id = notification.params.subscription; let matched_subscription_option = { let registry_guard = self.registry.lock().await; - registry_guard - .active_subscriptions - .get(&subscription_id) - .cloned() + registry_guard.active_subscriptions.get(&subscription_id).cloned() }; let resolution_subscription = matched_subscription_option.clone(); match matched_subscription_option { @@ -1178,13 +1178,13 @@ impl WsClient { notification: notification.clone(), method_matches_registry, }); - } + }, None => { self.emit_event(WsEvent::JsonRpcNotificationWithoutSubscription { endpoint_name: self.endpoint.name.clone(), notification: notification.clone(), }); - } + }, } forward_detection_notification_if_configured( &self.detection_notification_forwarder, @@ -1199,7 +1199,7 @@ impl WsClient { resolution_subscription, ) .await; - } + }, } } @@ -1370,7 +1370,7 @@ impl WsClient { return false; } *state_guard = crate::KbConnectionState::Disconnected; - true + return true; } fn emit_event(&self, event: WsEvent) { @@ -1388,19 +1388,13 @@ impl WsClient { &self, sender: tokio::sync::mpsc::Sender, ) { - let mut guard = self - .transaction_resolution_notification_forwarder - .lock() - .await; + let mut guard = self.transaction_resolution_notification_forwarder.lock().await; *guard = Some(sender); } /// Clears the optional transaction-resolution notification forwarder. pub async fn clear_transaction_resolution_notification_forwarder(&self) { - let mut guard = self - .transaction_resolution_notification_forwarder - .lock() - .await; + let mut guard = self.transaction_resolution_notification_forwarder.lock().await; *guard = None; } } @@ -1409,34 +1403,40 @@ fn kb_convert_outgoing_message( message: WsOutgoingMessage, ) -> tokio_tungstenite::tungstenite::Message { match message { - WsOutgoingMessage::Text(text) => tokio_tungstenite::tungstenite::Message::Text(text.into()), + WsOutgoingMessage::Text(text) => { + return tokio_tungstenite::tungstenite::Message::Text(text.into()); + }, WsOutgoingMessage::Binary(data) => { - tokio_tungstenite::tungstenite::Message::Binary(data.into()) - } - WsOutgoingMessage::Ping(data) => tokio_tungstenite::tungstenite::Message::Ping(data.into()), - WsOutgoingMessage::Pong(data) => tokio_tungstenite::tungstenite::Message::Pong(data.into()), - WsOutgoingMessage::Close => tokio_tungstenite::tungstenite::Message::Close(None), + return tokio_tungstenite::tungstenite::Message::Binary(data.into()); + }, + WsOutgoingMessage::Ping(data) => { + return tokio_tungstenite::tungstenite::Message::Ping(data.into()); + }, + WsOutgoingMessage::Pong(data) => { + return tokio_tungstenite::tungstenite::Message::Pong(data.into()); + }, + WsOutgoingMessage::Close => return tokio_tungstenite::tungstenite::Message::Close(None), } } fn kb_is_normal_close_error(error: &tokio_tungstenite::tungstenite::Error) -> bool { match error { - tokio_tungstenite::tungstenite::Error::ConnectionClosed => true, - tokio_tungstenite::tungstenite::Error::AlreadyClosed => true, - _ => false, + tokio_tungstenite::tungstenite::Error::ConnectionClosed => return true, + tokio_tungstenite::tungstenite::Error::AlreadyClosed => return true, + _ => return false, } } fn kb_json_value_to_u64(value: &serde_json::Value) -> std::option::Option { - value.as_u64() + return value.as_u64(); } fn kb_is_subscribe_method(method: &str) -> bool { - method.ends_with("Subscribe") + return method.ends_with("Subscribe"); } fn kb_is_unsubscribe_method(method: &str) -> bool { - method.ends_with("Unsubscribe") + return method.ends_with("Unsubscribe"); } fn kb_infer_unsubscribe_method_from_subscribe( @@ -1446,7 +1446,7 @@ fn kb_infer_unsubscribe_method_from_subscribe( return None; } let base = subscribe_method.trim_end_matches("Subscribe"); - Some(format!("{base}Unsubscribe")) + return Some(format!("{base}Unsubscribe")); } fn kb_infer_notification_method_from_subscribe( @@ -1456,7 +1456,7 @@ fn kb_infer_notification_method_from_subscribe( return None; } let base = subscribe_method.trim_end_matches("Subscribe"); - Some(format!("{base}Notification")) + return Some(format!("{base}Notification")); } fn kb_build_pending_json_rpc_request( @@ -1474,8 +1474,7 @@ fn kb_build_pending_json_rpc_request( Some(notification_method) => notification_method, None => return None, }; - let unsubscribe_method_option = - kb_infer_unsubscribe_method_from_subscribe(&request.method); + let unsubscribe_method_option = kb_infer_unsubscribe_method_from_subscribe(&request.method); let unsubscribe_method = match unsubscribe_method_option { Some(unsubscribe_method) => unsubscribe_method, None => return None, @@ -1510,11 +1509,11 @@ fn kb_build_pending_json_rpc_request( }, }); } - Some(WsPendingJsonRpcRequest { + return Some(WsPendingJsonRpcRequest { request_id, method: request.method.clone(), kind: WsPendingJsonRpcRequestKind::Generic, - }) + }); } fn kb_build_single_key_optional_config_params( @@ -1525,7 +1524,7 @@ fn kb_build_single_key_optional_config_params( if let Some(config) = config { params.push(config); } - params + return params; } fn kb_build_first_value_optional_config_params( @@ -1536,7 +1535,7 @@ fn kb_build_first_value_optional_config_params( if let Some(config) = config { params.push(config); } - params + return params; } async fn forward_detection_notification_if_configured( @@ -1564,21 +1563,21 @@ async fn forward_detection_notification_if_configured( ); let send_result = sender.try_send(envelope); match send_result { - Ok(()) => {} + Ok(()) => {}, Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => { tracing::warn!( target: "kb_lib::ws_client", "detection notification relay queue is full endpoint_name={}", endpoint_name ); - } + }, Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => { tracing::warn!( target: "kb_lib::ws_client", "detection notification relay queue is closed endpoint_name={}", endpoint_name ); - } + }, } } @@ -1609,21 +1608,21 @@ async fn forward_transaction_resolution_notification_if_configured( ); let send_result = sender.try_send(envelope); match send_result { - Ok(()) => {} + Ok(()) => {}, Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => { tracing::warn!( target: "kb_lib::ws_client", "transaction resolution relay queue is full endpoint_name={}", endpoint_name ); - } + }, Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => { tracing::warn!( target: "kb_lib::ws_client", "transaction resolution relay queue is closed endpoint_name={}", endpoint_name ); - } + }, } } @@ -1702,11 +1701,11 @@ mod tests { } } }); - Self { + return Self { url: format!("ws://{}", local_addr), shutdown_tx: Some(shutdown_tx), observed_methods, - } + }; } async fn spawn_json_rpc_server() -> Self { @@ -1817,16 +1816,16 @@ mod tests { } } }); - Self { + return Self { url: format!("ws://{}", local_addr), shutdown_tx: Some(shutdown_tx), observed_methods, - } + }; } async fn observed_methods_snapshot(&self) -> std::vec::Vec { let observed_methods_guard = self.observed_methods.lock().await; - observed_methods_guard.clone() + return observed_methods_guard.clone(); } async fn shutdown(mut self) { if let Some(shutdown_tx) = self.shutdown_tx.take() { @@ -1836,7 +1835,7 @@ mod tests { } fn make_ws_endpoint(url: std::string::String) -> crate::KbWsEndpointConfig { - crate::KbWsEndpointConfig { + return crate::KbWsEndpointConfig { name: "test_ws".to_string(), enabled: true, provider: "test".to_string(), @@ -1850,7 +1849,7 @@ mod tests { write_channel_capacity: 32, event_channel_capacity: 64, auto_reconnect: false, - } + }; } async fn recv_event( @@ -1859,7 +1858,7 @@ mod tests { let timeout_result = tokio::time::timeout(std::time::Duration::from_secs(2), receiver.recv()).await; let recv_result = timeout_result.expect("event receive timeout must not occur"); - recv_result.expect("event receive must succeed") + return recv_result.expect("event receive must succeed"); } #[tokio::test] @@ -1881,39 +1880,27 @@ mod tests { client.connect().await.expect("connect must succeed"); let connected_event = recv_event(&mut receiver).await; match connected_event { - crate::WsEvent::Connected { - endpoint_name, - endpoint_url, - } => { + crate::WsEvent::Connected { endpoint_name, endpoint_url } => { assert_eq!(endpoint_name, "test_ws"); assert_eq!(endpoint_url, server.url); - } + }, other => { panic!("unexpected connected event: {other:?}"); - } + }, } - client - .send_text("hello".to_string()) - .await - .expect("text send must succeed"); + client.send_text("hello".to_string()).await.expect("text send must succeed"); let text_event = recv_event(&mut receiver).await; match text_event { - crate::WsEvent::TextMessage { - endpoint_name, - text, - } => { + crate::WsEvent::TextMessage { endpoint_name, text } => { assert_eq!(endpoint_name, "test_ws"); assert_eq!(text, "hello"); - } + }, other => { panic!("unexpected text event: {other:?}"); - } + }, } client.disconnect().await.expect("disconnect must succeed"); - assert_eq!( - client.connection_state().await, - crate::KbConnectionState::Disconnected - ); + assert_eq!(client.connection_state().await, crate::KbConnectionState::Disconnected); let mut disconnected_seen = false; for _ in 0..4 { let event = recv_event(&mut receiver).await; @@ -1939,10 +1926,10 @@ mod tests { match error { crate::KbError::InvalidState(message) => { assert!(message.contains("cannot connect")); - } + }, other => { panic!("unexpected error variant: {other:?}"); - } + }, } client.disconnect().await.expect("disconnect must succeed"); server.shutdown().await; @@ -1956,22 +1943,16 @@ mod tests { let mut receiver = client.subscribe_events(); client.connect().await.expect("connect must succeed"); let _ = recv_event(&mut receiver).await; - client - .send_ping(vec![1, 2, 3, 4]) - .await - .expect("ping send must succeed"); + client.send_ping(vec![1, 2, 3, 4]).await.expect("ping send must succeed"); let event = recv_event(&mut receiver).await; match event { - crate::WsEvent::Pong { - endpoint_name, - data, - } => { + crate::WsEvent::Pong { endpoint_name, data } => { assert_eq!(endpoint_name, "test_ws"); assert_eq!(data, vec![1, 2, 3, 4]); - } + }, other => { panic!("unexpected event: {other:?}"); - } + }, } client.disconnect().await.expect("disconnect must succeed"); server.shutdown().await; @@ -1997,10 +1978,7 @@ mod tests { for _ in 0..8 { let event = recv_event(&mut receiver).await; match event { - crate::WsEvent::SubscriptionRegistered { - endpoint_name, - subscription, - } => { + crate::WsEvent::SubscriptionRegistered { endpoint_name, subscription } => { assert_eq!(endpoint_name, "test_ws"); assert_eq!(subscription.request_id, 1); assert_eq!(subscription.subscription_id, 77); @@ -2008,7 +1986,7 @@ mod tests { assert_eq!(subscription.unsubscribe_method, "slotUnsubscribe"); assert_eq!(subscription.notification_method, "slotNotification"); subscription_registered_seen = true; - } + }, crate::WsEvent::SubscriptionNotification { endpoint_name, subscription, @@ -2020,44 +1998,27 @@ mod tests { assert!(method_matches_registry); assert_eq!(notification.method, "slotNotification"); assert_eq!(notification.params.subscription, 77); - assert_eq!( - notification.params.result["slot"], - serde_json::Value::from(12u64) - ); + assert_eq!(notification.params.result["slot"], serde_json::Value::from(12u64)); subscription_notification_seen = true; - } - crate::WsEvent::TextMessage { .. } => {} - crate::WsEvent::JsonRpcMessage { .. } => {} + }, + crate::WsEvent::TextMessage { .. } => {}, + crate::WsEvent::JsonRpcMessage { .. } => {}, other => { panic!("unexpected event: {other:?}"); - } + }, } if subscription_registered_seen && subscription_notification_seen { break; } } - assert!( - subscription_registered_seen, - "subscription must be registered" - ); - assert!( - subscription_notification_seen, - "subscription notification must be routed" - ); + assert!(subscription_registered_seen, "subscription must be registered"); + assert!(subscription_notification_seen, "subscription notification must be routed"); assert_eq!(client.active_subscription_count().await, 1); assert_eq!(client.pending_request_count().await, 0); client.disconnect().await.expect("disconnect must succeed"); let observed_methods = server.observed_methods_snapshot().await; - assert!( - observed_methods - .iter() - .any(|method| method == "slotSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "slotUnsubscribe") - ); + assert!(observed_methods.iter().any(|method| return method == "slotSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "slotUnsubscribe")); server.shutdown().await; } @@ -2085,18 +2046,18 @@ mod tests { assert_eq!(response.error.message, "Method not found"); error_seen = true; break; - } + }, crate::KbJsonRpcWsIncomingMessage::SuccessResponse(other) => { panic!("unexpected success response: {other:?}"); - } + }, crate::KbJsonRpcWsIncomingMessage::Notification(other) => { panic!("unexpected notification: {other:?}"); - } + }, }, - crate::WsEvent::TextMessage { .. } => {} + crate::WsEvent::TextMessage { .. } => {}, other => { panic!("unexpected event: {other:?}"); - } + }, } } assert!(error_seen, "json-rpc error response must be observed"); @@ -2142,10 +2103,7 @@ mod tests { .await .expect("program_subscribe must succeed"); - let _ = client - .root_subscribe() - .await - .expect("root_subscribe must succeed"); + let _ = client.root_subscribe().await.expect("root_subscribe must succeed"); let _ = client .signature_subscribe_raw( "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b".to_string(), @@ -2153,65 +2111,23 @@ mod tests { ) .await .expect("signature_subscribe must succeed"); - let _ = client - .slot_subscribe() - .await - .expect("slot_subscribe must succeed"); + let _ = client.slot_subscribe().await.expect("slot_subscribe must succeed"); let _ = client .slots_updates_subscribe() .await .expect("slots_updates_subscribe must succeed"); - let _ = client - .vote_subscribe() - .await - .expect("vote_subscribe must succeed"); + let _ = client.vote_subscribe().await.expect("vote_subscribe must succeed"); tokio::time::sleep(std::time::Duration::from_millis(150)).await; let observed_methods = server.observed_methods_snapshot().await; - assert!( - observed_methods - .iter() - .any(|method| method == "accountSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "blockSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "logsSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "programSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "rootSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "signatureSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "slotSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "slotsUpdatesSubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "voteSubscribe") - ); + assert!(observed_methods.iter().any(|method| return method == "accountSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "blockSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "logsSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "programSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "rootSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "signatureSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "slotSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "slotsUpdatesSubscribe")); + assert!(observed_methods.iter().any(|method| return method == "voteSubscribe")); client.disconnect().await.expect("disconnect must succeed"); server.shutdown().await; } @@ -2228,85 +2144,34 @@ mod tests { .account_unsubscribe_raw(10) .await .expect("account_unsubscribe must succeed"); - let _ = client - .block_unsubscribe_raw(11) - .await - .expect("block_unsubscribe must succeed"); - let _ = client - .logs_unsubscribe_raw(12) - .await - .expect("logs_unsubscribe must succeed"); + let _ = client.block_unsubscribe_raw(11).await.expect("block_unsubscribe must succeed"); + let _ = client.logs_unsubscribe_raw(12).await.expect("logs_unsubscribe must succeed"); let _ = client .program_unsubscribe_raw(13) .await .expect("program_unsubscribe must succeed"); - let _ = client - .root_unsubscribe(14) - .await - .expect("root_unsubscribe must succeed"); + let _ = client.root_unsubscribe(14).await.expect("root_unsubscribe must succeed"); let _ = client .signature_unsubscribe_raw(15) .await .expect("signature_unsubscribe must succeed"); - let _ = client - .slot_unsubscribe(16) - .await - .expect("slot_unsubscribe must succeed"); + let _ = client.slot_unsubscribe(16).await.expect("slot_unsubscribe must succeed"); let _ = client .slots_updates_unsubscribe(17) .await .expect("slots_updates_unsubscribe must succeed"); - let _ = client - .vote_unsubscribe(18) - .await - .expect("vote_unsubscribe must succeed"); + let _ = client.vote_unsubscribe(18).await.expect("vote_unsubscribe must succeed"); tokio::time::sleep(std::time::Duration::from_millis(150)).await; let observed_methods = server.observed_methods_snapshot().await; - assert!( - observed_methods - .iter() - .any(|method| method == "accountUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "blockUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "logsUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "programUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "rootUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "signatureUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "slotUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "slotsUpdatesUnsubscribe") - ); - assert!( - observed_methods - .iter() - .any(|method| method == "voteUnsubscribe") - ); + assert!(observed_methods.iter().any(|method| return method == "accountUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "blockUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "logsUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "programUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "rootUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "signatureUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "slotUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "slotsUpdatesUnsubscribe")); + assert!(observed_methods.iter().any(|method| return method == "voteUnsubscribe")); client.disconnect().await.expect("disconnect must succeed"); server.shutdown().await; } @@ -2333,10 +2198,7 @@ mod tests { assert_eq!(envelope.endpoint_name.as_deref(), Some("test_ws")); assert_eq!(envelope.notification.method, "slotNotification"); assert_eq!(envelope.notification.params.subscription, 77); - assert_eq!( - envelope.notification.params.result["slot"], - serde_json::Value::from(12u64) - ); + assert_eq!(envelope.notification.params.result["slot"], serde_json::Value::from(12u64)); client.disconnect().await.expect("disconnect must succeed"); server.shutdown().await; } diff --git a/kb_lib/src/ws_hybrid_observation.rs b/kb_lib/src/ws_hybrid_observation.rs index 2ad7653..f922eb2 100644 --- a/kb_lib/src/ws_hybrid_observation.rs +++ b/kb_lib/src/ws_hybrid_observation.rs @@ -31,12 +31,12 @@ impl KbWsHybridObservationService { /// Creates a new hybrid WebSocket technical observation service. pub fn new(database: std::sync::Arc) -> Self { let persistence = crate::KbDetectionPersistenceService::new(database.clone()); - Self { + return Self { persistence, seen_dedupe_keys: std::sync::Arc::new(tokio::sync::Mutex::new( std::collections::HashSet::::new(), )), - } + }; } /// Records one `logsNotification` payload. @@ -46,14 +46,15 @@ impl KbWsHybridObservationService { payload: &serde_json::Value, ) -> Result { let signature = kb_extract_string_by_candidate_keys(payload, &["signature"]); - self.record_observation_inner( - "ws.hybrid.logs_notification".to_string(), - "signal.ws.hybrid.logs_notification".to_string(), - endpoint_name, - signature, - payload, - ) - .await + return self + .record_observation_inner( + "ws.hybrid.logs_notification".to_string(), + "signal.ws.hybrid.logs_notification".to_string(), + endpoint_name, + signature, + payload, + ) + .await; } /// Records one `programNotification` payload for one watched program id. @@ -68,14 +69,15 @@ impl KbWsHybridObservationService { Some(pubkey) => Some(pubkey), None => Some(watched_program_id), }; - self.record_observation_inner( - "ws.hybrid.program_notification".to_string(), - "signal.ws.hybrid.program_notification".to_string(), - endpoint_name, - watched_address, - payload, - ) - .await + return self + .record_observation_inner( + "ws.hybrid.program_notification".to_string(), + "signal.ws.hybrid.program_notification".to_string(), + endpoint_name, + watched_address, + payload, + ) + .await; } /// Records one `accountNotification` payload for one watched account address. @@ -85,14 +87,15 @@ impl KbWsHybridObservationService { watched_account: std::string::String, payload: &serde_json::Value, ) -> Result { - self.record_observation_inner( - "ws.hybrid.account_notification".to_string(), - "signal.ws.hybrid.account_notification".to_string(), - endpoint_name, - Some(watched_account), - payload, - ) - .await + return self + .record_observation_inner( + "ws.hybrid.account_notification".to_string(), + "signal.ws.hybrid.account_notification".to_string(), + endpoint_name, + Some(watched_account), + payload, + ) + .await; } async fn record_observation_inner( @@ -156,18 +159,18 @@ impl KbWsHybridObservationService { if let Err(error) = signal_result { return Err(error); } - Ok(crate::KbWsHybridObservationResult { + return Ok(crate::KbWsHybridObservationResult { observation_name, dedupe_key, watched_address, slot, created_observation: true, - }) + }); } } fn kb_extract_slot(value: &serde_json::Value) -> std::option::Option { - kb_extract_u64_by_candidate_keys(value, &["slot"]) + return kb_extract_u64_by_candidate_keys(value, &["slot"]); } fn kb_extract_string_by_candidate_keys( @@ -200,7 +203,7 @@ fn kb_extract_string_by_candidate_keys( } } } - None + return None; } fn kb_extract_u64_by_candidate_keys( @@ -233,7 +236,7 @@ fn kb_extract_u64_by_candidate_keys( } } } - None + return None; } fn kb_hash_payload(payload: &serde_json::Value) -> std::string::String { @@ -244,7 +247,7 @@ fn kb_hash_payload(payload: &serde_json::Value) -> std::string::String { }; let mut hasher = std::collections::hash_map::DefaultHasher::new(); std::hash::Hash::hash(&payload_text, &mut hasher); - hasher.finish().to_string() + return hasher.finish().to_string(); } fn kb_build_ws_observation_dedupe_key( @@ -254,14 +257,14 @@ fn kb_build_ws_observation_dedupe_key( slot: std::option::Option, payload_hash: &str, ) -> std::string::String { - format!( + return format!( "{}:{}:{}:{}:{}", source_method, endpoint_name.unwrap_or_default(), address.unwrap_or_default(), slot.unwrap_or_default(), payload_hash - ) + ); } #[cfg(test)] @@ -290,7 +293,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } #[tokio::test] diff --git a/kb_lib/src/ws_hybrid_runtime.rs b/kb_lib/src/ws_hybrid_runtime.rs index f04b2ac..8766ad4 100644 --- a/kb_lib/src/ws_hybrid_runtime.rs +++ b/kb_lib/src/ws_hybrid_runtime.rs @@ -15,17 +15,14 @@ impl KbWsHybridRuntimeService { pub fn new(database: std::sync::Arc) -> Self { let watch_service = crate::KbWsHybridWatchService::new(database.clone()); let observation_service = crate::KbWsHybridObservationService::new(database); - Self { - watch_service, - observation_service, - } + return Self { watch_service, observation_service }; } /// Collects the current hybrid watch snapshot. pub async fn collect_watch_snapshot( &self, ) -> Result { - self.watch_service.collect_snapshot().await + return self.watch_service.collect_snapshot().await; } /// Records one `logsNotification` payload. @@ -34,9 +31,7 @@ impl KbWsHybridRuntimeService { endpoint_name: std::option::Option, payload: &serde_json::Value, ) -> Result { - self.observation_service - .record_logs_notification(endpoint_name, payload) - .await + return self.observation_service.record_logs_notification(endpoint_name, payload).await; } /// Records one `programNotification` payload. @@ -46,9 +41,10 @@ impl KbWsHybridRuntimeService { watched_program_id: std::string::String, payload: &serde_json::Value, ) -> Result { - self.observation_service + return self + .observation_service .record_program_notification(endpoint_name, watched_program_id, payload) - .await + .await; } /// Records one `accountNotification` payload. @@ -58,9 +54,10 @@ impl KbWsHybridRuntimeService { watched_account: std::string::String, payload: &serde_json::Value, ) -> Result { - self.observation_service + return self + .observation_service .record_account_notification(endpoint_name, watched_account, payload) - .await + .await; } } @@ -90,7 +87,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_dexes_and_pools(database: std::sync::Arc) { diff --git a/kb_lib/src/ws_hybrid_watch.rs b/kb_lib/src/ws_hybrid_watch.rs index 07841d7..4841a6a 100644 --- a/kb_lib/src/ws_hybrid_watch.rs +++ b/kb_lib/src/ws_hybrid_watch.rs @@ -40,7 +40,7 @@ pub struct KbWsHybridWatchService { impl KbWsHybridWatchService { /// Creates a new hybrid watch-target collection service. pub fn new(database: std::sync::Arc) -> Self { - Self { database } + return Self { database }; } /// Collects the deduplicated set of DEX program targets. @@ -79,8 +79,8 @@ impl KbWsHybridWatchService { } } } - targets.sort_by(|left, right| left.address.cmp(&right.address)); - Ok(targets) + targets.sort_by(|left, right| return left.address.cmp(&right.address)); + return Ok(targets); } /// Collects the deduplicated set of active pool-account targets. @@ -111,8 +111,8 @@ impl KbWsHybridWatchService { logical_source: format!("pool:{}", pool.dex_id), }); } - targets.sort_by(|left, right| left.address.cmp(&right.address)); - Ok(targets) + targets.sort_by(|left, right| return left.address.cmp(&right.address)); + return Ok(targets); } /// Collects both program and account targets in one snapshot. @@ -127,10 +127,7 @@ impl KbWsHybridWatchService { Ok(account_targets) => account_targets, Err(error) => return Err(error), }; - Ok(crate::KbWsHybridWatchSnapshot { - program_targets, - account_targets, - }) + return Ok(crate::KbWsHybridWatchSnapshot { program_targets, account_targets }); } } @@ -160,7 +157,7 @@ mod tests { Ok(database) => database, Err(error) => panic!("database init must succeed: {}", error), }; - std::sync::Arc::new(database) + return std::sync::Arc::new(database); } async fn seed_dexes_and_pools(database: std::sync::Arc) { let dex_a = crate::KbDexDto::new( @@ -276,9 +273,6 @@ mod tests { addresses.push(target.address.clone()); } addresses.sort(); - assert_eq!( - addresses, - vec!["PoolAddress111".to_string(), "PoolAddress222".to_string(),] - ); + assert_eq!(addresses, vec!["PoolAddress111".to_string(), "PoolAddress222".to_string(),]); } } diff --git a/kb_lib/src/ws_manager.rs b/kb_lib/src/ws_manager.rs index 3ff08a7..e2c3b7e 100644 --- a/kb_lib/src/ws_manager.rs +++ b/kb_lib/src/ws_manager.rs @@ -93,13 +93,10 @@ impl WsManager { spawn_event_forward_task(client.clone(), event_tx.clone()); clients.insert( endpoint.name.clone(), - WsManagedClient { - client, - event_forward_abort_handle, - }, + WsManagedClient { client, event_forward_abort_handle }, ); } - Ok(Self { + return Ok(Self { clients: tokio::sync::Mutex::new(clients), event_tx, detection_relay_sender: tokio::sync::Mutex::new(None), @@ -107,23 +104,23 @@ impl WsManager { transaction_resolution_relay_sender: tokio::sync::Mutex::new(None), transaction_resolution_relay_abort_handle: tokio::sync::Mutex::new(None), hybrid_observation_relay_abort_handle: tokio::sync::Mutex::new(None), - }) + }); } /// Builds one manager from the application configuration. pub fn from_config(config: &crate::KbConfig) -> Result { - Self::from_ws_endpoints(&config.solana.ws_endpoints) + return Self::from_ws_endpoints(&config.solana.ws_endpoints); } /// Returns a unified broadcast receiver for all managed client events. pub fn subscribe_events(&self) -> tokio::sync::broadcast::Receiver { - self.event_tx.subscribe() + return self.event_tx.subscribe(); } /// Returns the list of managed endpoint names. pub async fn endpoint_names(&self) -> std::vec::Vec { let clients_guard = self.clients.lock().await; - clients_guard.keys().cloned().collect() + return clients_guard.keys().cloned().collect(); } /// Returns the list of managed endpoint names having the requested role. @@ -136,12 +133,12 @@ impl WsManager { .endpoint_config() .roles .iter() - .any(|configured_role| configured_role == role) + .any(|configured_role| return configured_role == role) { endpoint_names.push(endpoint_name.clone()); } } - endpoint_names + return endpoint_names; } /// Starts all managed endpoints having the requested role. @@ -158,7 +155,7 @@ impl WsManager { started_count += 1; } } - Ok(started_count) + return Ok(started_count); } /// Stops all managed endpoints having the requested role. @@ -175,7 +172,7 @@ impl WsManager { stopped_count += 1; } } - Ok(stopped_count) + return Ok(stopped_count); } /// Returns one managed client by endpoint name. @@ -183,8 +180,8 @@ impl WsManager { let clients_guard = self.clients.lock().await; let managed_option = clients_guard.get(endpoint_name); match managed_option { - Some(managed) => Some(managed.client.clone()), - None => None, + Some(managed) => return Some(managed.client.clone()), + None => return None, } } @@ -197,7 +194,7 @@ impl WsManager { "unknown managed websocket endpoint '{}'", endpoint_name ))); - } + }, }; let state = client.connection_state().await; if state == crate::KbConnectionState::Connected @@ -217,23 +214,21 @@ impl WsManager { sender_guard.clone() }; if let Some(sender) = tx_resolution_sender_option { - client - .set_transaction_resolution_notification_forwarder(sender) - .await; + client.set_transaction_resolution_notification_forwarder(sender).await; } let connect_result = client.connect().await; if let Err(error) = connect_result { return Err(error); } - Ok(true) + return Ok(true); } /// Starts one managed endpoint. pub async fn start_endpoint(&self, endpoint_name: &str) -> Result<(), crate::KbError> { let start_result = self.start_endpoint_inner(endpoint_name).await; match start_result { - Ok(_) => Ok(()), - Err(error) => Err(error), + Ok(_) => return Ok(()), + Err(error) => return Err(error), } } @@ -246,7 +241,7 @@ impl WsManager { "unknown managed websocket endpoint '{}'", endpoint_name ))); - } + }, }; let state = client.connection_state().await; if state == crate::KbConnectionState::Disconnected @@ -255,22 +250,20 @@ impl WsManager { return Ok(false); } client.clear_detection_notification_forwarder().await; - client - .clear_transaction_resolution_notification_forwarder() - .await; + client.clear_transaction_resolution_notification_forwarder().await; let disconnect_result = client.disconnect().await; if let Err(error) = disconnect_result { return Err(error); } - Ok(true) + return Ok(true); } /// Stops one managed endpoint. pub async fn stop_endpoint(&self, endpoint_name: &str) -> Result<(), crate::KbError> { let stop_result = self.stop_endpoint_inner(endpoint_name).await; match stop_result { - Ok(_) => Ok(()), - Err(error) => Err(error), + Ok(_) => return Ok(()), + Err(error) => return Err(error), } } @@ -288,7 +281,7 @@ impl WsManager { started_count += 1; } } - Ok(started_count) + return Ok(started_count); } /// Stops all managed endpoints. @@ -305,7 +298,7 @@ impl WsManager { stopped_count += 1; } } - Ok(stopped_count) + return Ok(stopped_count); } /// Returns the number of active subscriptions for one endpoint. @@ -321,9 +314,9 @@ impl WsManager { "unknown managed websocket endpoint '{}'", endpoint_name ))); - } + }, }; - Ok(client.active_subscription_count().await) + return Ok(client.active_subscription_count().await); } /// Returns a consolidated snapshot of all managed endpoints. @@ -353,11 +346,11 @@ impl WsManager { active_subscription_count, }); } - Ok(WsManagerSnapshot { + return Ok(WsManagerSnapshot { endpoint_count: endpoints.len(), started_count, endpoints, - }) + }); } /// Attaches one shared detection relay to all managed clients. @@ -398,11 +391,9 @@ impl WsManager { values }; for client in clients { - client - .set_detection_notification_forwarder(sender.clone()) - .await; + client.set_detection_notification_forwarder(sender.clone()).await; } - Ok(()) + return Ok(()); } /// Detaches the shared detection relay from all managed clients. @@ -429,13 +420,13 @@ impl WsManager { if let Some(abort_handle) = abort_handle_option { abort_handle.abort(); } - Ok(()) + return Ok(()); } /// Returns whether one managed endpoint exists. pub async fn has_endpoint(&self, endpoint_name: &str) -> bool { let clients_guard = self.clients.lock().await; - clients_guard.contains_key(endpoint_name) + return clients_guard.contains_key(endpoint_name); } /// Returns the current connection state of one endpoint. @@ -451,9 +442,9 @@ impl WsManager { "unknown managed websocket endpoint '{}'", endpoint_name ))); - } + }, }; - Ok(client.connection_state().await) + return Ok(client.connection_state().await); } /// Attaches one shared transaction-resolution relay to all managed clients. @@ -494,11 +485,9 @@ impl WsManager { values }; for client in clients { - client - .set_transaction_resolution_notification_forwarder(sender.clone()) - .await; + client.set_transaction_resolution_notification_forwarder(sender.clone()).await; } - Ok(()) + return Ok(()); } /// Detaches the shared transaction-resolution relay from all managed clients. @@ -512,9 +501,7 @@ impl WsManager { values }; for client in clients { - client - .clear_transaction_resolution_notification_forwarder() - .await; + client.clear_transaction_resolution_notification_forwarder().await; } { let mut sender_guard = self.transaction_resolution_relay_sender.lock().await; @@ -527,7 +514,7 @@ impl WsManager { if let Some(abort_handle) = abort_handle_option { abort_handle.abort(); } - Ok(()) + return Ok(()); } /// Collects the current hybrid WebSocket watch snapshot. @@ -536,7 +523,7 @@ impl WsManager { database: std::sync::Arc, ) -> Result { let runtime = crate::KbWsHybridRuntimeService::new(database); - runtime.collect_watch_snapshot().await + return runtime.collect_watch_snapshot().await; } /// Attaches one shared hybrid observation relay to the manager event stream. @@ -559,7 +546,7 @@ impl WsManager { let mut abort_guard = self.hybrid_observation_relay_abort_handle.lock().await; *abort_guard = Some(abort_handle); } - Ok(()) + return Ok(()); } /// Detaches the shared hybrid observation relay from the manager event stream. @@ -571,7 +558,7 @@ impl WsManager { if let Some(abort_handle) = abort_handle_option { abort_handle.abort(); } - Ok(()) + return Ok(()); } } @@ -615,15 +602,15 @@ fn spawn_event_forward_task( match recv_result { Ok(event) => { let _ = event_tx.send(event); - } - Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {} + }, + Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {}, Err(tokio::sync::broadcast::error::RecvError::Closed) => { break; - } + }, } } }); - task.abort_handle() + return task.abort_handle(); } fn spawn_hybrid_observation_relay_task( @@ -636,16 +623,15 @@ fn spawn_hybrid_observation_relay_task( match recv_result { Ok(event) => { handle_hybrid_observation_manager_event(&runtime, event).await; - } - Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {} + }, + Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {}, Err(tokio::sync::broadcast::error::RecvError::Closed) => { break; - } + }, } } }); - - task.abort_handle() + return task.abort_handle(); } async fn handle_hybrid_observation_manager_event( @@ -666,11 +652,8 @@ async fn handle_hybrid_observation_manager_event( notification, ) .await; - } - crate::WsEvent::JsonRpcNotificationWithoutSubscription { - endpoint_name, - notification, - } => { + }, + crate::WsEvent::JsonRpcNotificationWithoutSubscription { endpoint_name, notification } => { if notification.method == "logsNotification" { let value_result = serde_json::to_value(notification.clone()); let value = match value_result { @@ -682,11 +665,10 @@ async fn handle_hybrid_observation_manager_event( error ); return; - } + }, }; - let record_result = runtime - .record_logs_notification(Some(endpoint_name), &value) - .await; + let record_result = + runtime.record_logs_notification(Some(endpoint_name), &value).await; if let Err(error) = record_result { tracing::warn!( target: "kb_lib::ws_manager", @@ -695,8 +677,8 @@ async fn handle_hybrid_observation_manager_event( ); } } - } - _ => {} + }, + _ => {}, } } @@ -716,13 +698,11 @@ async fn handle_hybrid_subscription_notification( error ); return; - } + }, }; let method = notification.method.as_str(); if method == "logsNotification" { - let record_result = runtime - .record_logs_notification(Some(endpoint_name), &value) - .await; + let record_result = runtime.record_logs_notification(Some(endpoint_name), &value).await; if let Err(error) = record_result { tracing::warn!( target: "kb_lib::ws_manager", @@ -742,7 +722,7 @@ async fn handle_hybrid_subscription_notification( "missing watched program id in subscription params" ); return; - } + }, }; let record_result = runtime .record_program_notification(Some(endpoint_name), watched_program_id, &value) @@ -766,7 +746,7 @@ async fn handle_hybrid_subscription_notification( "missing watched account in subscription params" ); return; - } + }, }; let record_result = runtime .record_account_notification(Some(endpoint_name), watched_account, &value) @@ -791,8 +771,8 @@ fn kb_first_subscription_param_as_string( }; let text_option = first_param.as_str(); match text_option { - Some(text) => Some(text.to_string()), - None => None, + Some(text) => return Some(text.to_string()), + None => return None, } } @@ -881,10 +861,10 @@ mod tests { } } }); - Self { + return Self { url: format!("ws://{}", local_addr), shutdown_tx: Some(shutdown_tx), - } + }; } async fn spawn_json_rpc_server() -> Self { @@ -1023,10 +1003,10 @@ mod tests { } } }); - Self { + return Self { url: format!("ws://{}", local_addr), shutdown_tx: Some(shutdown_tx), - } + }; } async fn spawn_hybrid_json_rpc_server() -> Self { @@ -1230,10 +1210,10 @@ mod tests { } } }); - Self { + return Self { url: format!("ws://{}", local_addr), shutdown_tx: Some(shutdown_tx), - } + }; } async fn shutdown(mut self) { @@ -1248,7 +1228,7 @@ mod tests { url: std::string::String, enabled: bool, ) -> crate::KbWsEndpointConfig { - crate::KbWsEndpointConfig { + return crate::KbWsEndpointConfig { name: name.to_string(), enabled, provider: "test".to_string(), @@ -1262,7 +1242,7 @@ mod tests { write_channel_capacity: 32, event_channel_capacity: 64, auto_reconnect: false, - } + }; } async fn recv_manager_event( @@ -1275,7 +1255,7 @@ mod tests { Err(_) => panic!("manager event receive timeout"), }; match recv_result { - Ok(event) => event, + Ok(event) => return event, Err(error) => panic!("manager event receive failed: {error}"), } } @@ -1301,7 +1281,7 @@ mod tests { }; let database_result = crate::KbDatabase::connect_and_initialize(&config).await; match database_result { - Ok(database) => database, + Ok(database) => return database, Err(error) => panic!("database init failed: {error}"), } } @@ -1385,10 +1365,7 @@ mod tests { assert_eq!(snapshot.started_count, 1); assert_eq!(snapshot.endpoints.len(), 1); assert_eq!(snapshot.endpoints[0].endpoint_name, "ws_a"); - assert_eq!( - snapshot.endpoints[0].state, - crate::KbConnectionState::Connected - ); + assert_eq!(snapshot.endpoints[0].state, crate::KbConnectionState::Connected); let stop_result = manager.stop_all().await; if let Err(error) = stop_result { panic!("stop_all failed: {error}"); @@ -1571,11 +1548,7 @@ mod tests { #[tokio::test] async fn collect_hybrid_watch_snapshot_reads_dexes_and_active_pools() { - let endpoints = vec![make_ws_endpoint( - "ws_a", - "ws://127.0.0.1:1".to_string(), - true, - )]; + let endpoints = vec![make_ws_endpoint("ws_a", "ws://127.0.0.1:1".to_string(), true)]; let manager_result = crate::WsManager::from_ws_endpoints(&endpoints); let manager = match manager_result { Ok(manager) => manager, @@ -1594,10 +1567,7 @@ mod tests { assert_eq!(snapshot.program_targets.len(), 3); assert_eq!(snapshot.account_targets.len(), 1); - assert_eq!( - snapshot.account_targets[0].address, - "HybridPool111".to_string() - ); + assert_eq!(snapshot.account_targets[0].address, "HybridPool111".to_string()); } #[tokio::test] @@ -1611,9 +1581,7 @@ mod tests { }; let database = create_database().await; let database = std::sync::Arc::new(database); - let attach_result = manager - .attach_hybrid_observation_relay(database.clone()) - .await; + let attach_result = manager.attach_hybrid_observation_relay(database.clone()).await; if let Err(error) = attach_result { panic!("attach_hybrid_observation_relay failed: {error}"); } @@ -1626,21 +1594,17 @@ mod tests { Some(client) => client, None => panic!("client must exist"), }; - let logs_subscribe_result = client - .logs_subscribe_raw(serde_json::json!("all"), None) - .await; + let logs_subscribe_result = client.logs_subscribe_raw(serde_json::json!("all"), None).await; if let Err(error) = logs_subscribe_result { panic!("logsSubscribe failed: {error}"); } - let program_subscribe_result = client - .program_subscribe_raw("HybridProgram111".to_string(), None) - .await; + let program_subscribe_result = + client.program_subscribe_raw("HybridProgram111".to_string(), None).await; if let Err(error) = program_subscribe_result { panic!("programSubscribe failed: {error}"); } - let account_subscribe_result = client - .account_subscribe_raw("HybridPool111".to_string(), None) - .await; + let account_subscribe_result = + client.account_subscribe_raw("HybridPool111".to_string(), None).await; if let Err(error) = account_subscribe_result { panic!("accountSubscribe failed: {error}"); } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..09a40c5 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,38 @@ +# file: rustfmt.toml + +edition = "2024" +newline_style = "Unix" +use_small_heuristics = "Default" +hard_tabs = false +tab_spaces = 4 +max_width = 100 +chain_width = 80 +fn_call_width = 80 +attr_fn_like_width = 80 +struct_lit_width = 40 +struct_variant_width = 40 +array_width = 80 +single_line_if_else_max_width = 80 +single_line_let_else_max_width = 80 +imports_indent = "Block" +group_imports = "StdExternalCrate" +imports_granularity = "Module" +reorder_imports = true +reorder_modules = true +normalize_comments = false +normalize_doc_attributes = false +format_code_in_doc_comments = false +wrap_comments = false +format_strings = false +hex_literal_case = "Lower" +empty_item_single_line = true +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_arm_blocks = true +match_block_trailing_comma = true +trailing_comma = "Vertical" +use_field_init_shorthand = true +use_try_shorthand = false +force_explicit_abi = true +condense_wildcard_suffixes = false +unstable_features = false