0.7.38-B
This commit is contained in:
@@ -69,3 +69,4 @@
|
|||||||
0.7.36 - Consolidation de la famille Meteora : corpus mixte `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlmm`, correction des discriminants DAMM v2 / DBC, validation du profil `0.7.36_meteora_family_consolidation`, et reclassement explicite des swaps DAMM v2 / DBC sans payload montant/prix en `non_actionable_trade` afin d’éviter tout trade/candle artificiel.
|
0.7.36 - Consolidation de la famille Meteora : corpus mixte `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlmm`, correction des discriminants DAMM v2 / DBC, validation du profil `0.7.36_meteora_family_consolidation`, et reclassement explicite des swaps DAMM v2 / DBC sans payload montant/prix en `non_actionable_trade` afin d’éviter tout trade/candle artificiel.
|
||||||
0.7.37 - Première tranche metadata/catalog : ajout du profil `0.7.37_token_metadata_catalog_enrichment`, exposition des compteurs metadata dans diagnostics/validation et raccordement UI Demo Pipeline 2 sans rendre les metadata manquantes bloquantes.
|
0.7.37 - Première tranche metadata/catalog : ajout du profil `0.7.37_token_metadata_catalog_enrichment`, exposition des compteurs metadata dans diagnostics/validation et raccordement UI Demo Pipeline 2 sans rendre les metadata manquantes bloquantes.
|
||||||
0.7.38 - Priorisation des metadata manquantes : ajout du profil `0.7.38_token_metadata_gap_prioritization`, samples `tokenMetadataGapSamples`, priorités tradable/quote/catalog, raccordement UI Demo Pipeline 2 et maintien du caractère non bloquant des metadata incomplètes.
|
0.7.38 - Priorisation des metadata manquantes : ajout du profil `0.7.38_token_metadata_gap_prioritization`, samples `tokenMetadataGapSamples`, priorités tradable/quote/catalog, raccordement UI Demo Pipeline 2 et maintien du caractère non bloquant des metadata incomplètes.
|
||||||
|
0.7.39 - Tranche sûre launch surfaces : ensemencement contrôlé des origins LaunchLab/Launchpad/LetsBonk/Bonk.fun/Bags/Moonshot/Moonit/Boop.fun/Believe, Heaven préparé mais désactivé, mappings génériques vérifiés, samples diagnostics `launchOriginSamples` / `poolOriginSamples`, profil `0.7.39_launch_surface_origin_baseline`, raccordement Demo Pipeline 2 et maintien de l’invariant sans faux trade/candle ni program id fictif.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.7.38"
|
version = "0.7.39"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||||
|
|||||||
98
README.md
98
README.md
@@ -4,15 +4,15 @@
|
|||||||
|
|
||||||
`khadhroony-bobobot` est un workspace Rust destiné à la détection, au décodage, à l’analyse et, à terme, au trading semi-automatisé de tokens Solana.
|
`khadhroony-bobobot` est un workspace Rust destiné à la détection, au décodage, à l’analyse et, à terme, au trading semi-automatisé de tokens Solana.
|
||||||
|
|
||||||
Le README précédent décrivait surtout l’état `0.3.1`. Ce fichier reflète l’état de clôture `0.7.38` et la reprise prévue en `0.7.39` : le socle transport HTTP/WS, la résolution transactionnelle, le modèle SQLite, plusieurs connecteurs DEX, les candles, les signaux analytiques, la validation locale, la matrice DEX commune et les diagnostics de metadata prioritaires existent déjà.
|
Le README précédent décrivait surtout l’état `0.3.1`. Ce fichier reflète l’état de clôture `0.7.38-B` et la réorientation de travail `0.7.39 DEX-first` : le socle transport HTTP/WS, la résolution transactionnelle, le modèle SQLite, plusieurs connecteurs DEX, les candles, les signaux analytiques, la validation locale, la matrice DEX commune et les diagnostics de metadata prioritaires existent déjà. La prochaine phase donne la priorité aux DEX effectifs sur lesquels les swaps et événements de marché sont observables, avant de revenir aux launch surfaces.
|
||||||
|
|
||||||
## 1. Objectif
|
## 1. Objectif
|
||||||
|
|
||||||
L’objectif opérationnel est de construire progressivement une application capable de :
|
L’objectif opérationnel est de construire progressivement une application capable de :
|
||||||
|
|
||||||
- détecter l’apparition de nouveaux tokens, pools, paires et listings sur Solana ;
|
- détecter l’apparition de nouveaux tokens, pools, paires et listings sur Solana ;
|
||||||
- identifier la première source de mint ou de lancement, même lorsque le token migre ensuite vers un autre DEX ;
|
- identifier en priorité les DEX effectifs sur lesquels les swaps, liquidités et événements de marché sont réellement exécutés ;
|
||||||
- décoder les transactions pertinentes des DEX et launch surfaces ciblés ;
|
- décoder les transactions pertinentes des DEX ciblés, puis seulement ensuite les launch surfaces et origines de mint/lancement ;
|
||||||
- séparer les swaps/candles des événements utiles seulement à l’analyse : liquidité, cycle de vie de pool, fees, rewards, administration, wallets observés ;
|
- séparer les swaps/candles des événements utiles seulement à l’analyse : liquidité, cycle de vie de pool, fees, rewards, administration, wallets observés ;
|
||||||
- produire des métriques exploitables : prix, volume, candles/OHLCV, activité, bursts, déséquilibres buy/sell, signaux analytiques ;
|
- produire des métriques exploitables : prix, volume, candles/OHLCV, activité, bursts, déséquilibres buy/sell, signaux analytiques ;
|
||||||
- préparer ensuite des règles déterministes de filtrage, d’achat, de vente, de stop-loss et de trailing stop ;
|
- préparer ensuite des règles déterministes de filtrage, d’achat, de vente, de stop-loss et de trailing stop ;
|
||||||
@@ -31,7 +31,7 @@ Le workspace contient deux crates principales.
|
|||||||
|
|
||||||
La logique métier doit rester dans `kb_lib`. `kb_demo_app` doit rester une façade UI/Tauri et ne doit pas récupérer de logique Solana ou DEX profonde.
|
La logique métier doit rester dans `kb_lib`. `kb_demo_app` doit rester une façade UI/Tauri et ne doit pas récupérer de logique Solana ou DEX profonde.
|
||||||
|
|
||||||
## 3. État actuel après `0.7.38`
|
## 3. État actuel après `0.7.38-B`
|
||||||
|
|
||||||
### 3.1. Socle stabilisé à ne pas refactorer maintenant
|
### 3.1. Socle stabilisé à ne pas refactorer maintenant
|
||||||
|
|
||||||
@@ -74,16 +74,20 @@ Les connecteurs suivants sont les surfaces actuellement les plus importantes pou
|
|||||||
- `meteora_damm_v2`, observé dans le corpus `0.7.36`, mais les swaps sans payload montant/prix exploitable sont maintenant `non_actionable_trade` ;
|
- `meteora_damm_v2`, observé dans le corpus `0.7.36`, mais les swaps sans payload montant/prix exploitable sont maintenant `non_actionable_trade` ;
|
||||||
- `meteora_dbc`, observé dans le corpus `0.7.36`, mais les swaps sans payload montant/prix exploitable sont maintenant `non_actionable_trade`.
|
- `meteora_dbc`, observé dans le corpus `0.7.36`, mais les swaps sans payload montant/prix exploitable sont maintenant `non_actionable_trade`.
|
||||||
|
|
||||||
### 3.4. Connecteurs déjà présents mais à consolider par corpus
|
### 3.4. Connecteurs à consolider par corpus en priorité DEX-first
|
||||||
|
|
||||||
Les modules suivants existent ou sont partiellement représentés dans le code, mais doivent encore être consolidés par corpus local, invariants et documentation :
|
Les modules ou surfaces suivantes existent, sont partiellement représentés dans le code ou doivent être recherchés, mais doivent être consolidés par corpus local, invariants et documentation avant de reprendre les launch surfaces :
|
||||||
|
|
||||||
|
- `raydium_amm_v4` legacy ;
|
||||||
|
- `raydium_stable_swap` ;
|
||||||
- `orca_whirlpools` ;
|
- `orca_whirlpools` ;
|
||||||
- `fluxbeam` ;
|
- `fluxbeam` ;
|
||||||
- `dexlab` ;
|
- `dexlab` ;
|
||||||
- `raydium_amm_v4` legacy ;
|
- `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlmm` pour la couverture non-trade complète ;
|
||||||
- launch origins déjà amorcées : `meteora_fun_launch`, `bags`, `moonit` ;
|
- `metaDAO` et `printr`, apparus comme DEX à vérifier côté sources externes de découverte ;
|
||||||
- launch surfaces à venir : `raydium_launchlab`, `raydium_launchpad`, `letsbonk` / `bonk`, `boop_fun`, `moonshot`, `believe`, `heaven`.
|
- tout DEX ou programme récurrent détecté dans `k_sol_protocol_candidates`, DEX Screener ou les transactions locales.
|
||||||
|
|
||||||
|
Les launch origins déjà amorcées (`meteora_fun_launch`, `bags`, `moonit`) et les launch surfaces enregistrables (`raydium_launchlab`, `raydium_launchpad`, `letsbonk`, `bonk_fun`, `bags`, `moonshot`, `moonit`, `boop_fun`, `believe`, `heaven`) sont conservées dans la documentation, mais elles ne sont plus prioritaires tant que les DEX effectifs ne sont pas suffisamment couverts.
|
||||||
|
|
||||||
### 3.5. Validation acquise en `0.7.36`
|
### 3.5. Validation acquise en `0.7.36`
|
||||||
|
|
||||||
@@ -100,13 +104,13 @@ La validation `0.7.36_meteora_family_consolidation` est considérée comme réal
|
|||||||
|
|
||||||
Point important : `meteora_damm_v2` et `meteora_dbc` peuvent produire beaucoup d’événements `swap` décodés sans produire de `trade_events` lorsque les montants ou prix ne sont pas fiables. Ces événements doivent rester `non_actionable_trade` et ne doivent pas être comptés comme `tradeCandidate` ou `candleCandidate`.
|
Point important : `meteora_damm_v2` et `meteora_dbc` peuvent produire beaucoup d’événements `swap` décodés sans produire de `trade_events` lorsque les montants ou prix ne sont pas fiables. Ces événements doivent rester `non_actionable_trade` et ne doivent pas être comptés comme `tradeCandidate` ou `candleCandidate`.
|
||||||
|
|
||||||
## 4. Matrice DEX et launch surfaces
|
## 4. Matrice DEX : DEX effectifs d’abord, launch surfaces ensuite
|
||||||
|
|
||||||
La distinction importante est la suivante :
|
La distinction de travail à partir de `0.7.39` est la suivante :
|
||||||
|
|
||||||
- un **DEX effectif** permet de détecter et décoder des swaps, pools, liquidité et candles ;
|
- un **DEX effectif** est un programme ou une famille de programmes sur lesquels des swaps, pools, liquidités, fees, rewards, admin/config, burns ou mints utiles sont réellement observables ;
|
||||||
- une **launch surface** peut être la première source de mint ou de lancement, même si le token migre ensuite vers Raydium, Meteora ou un autre AMM ;
|
- une **launch surface** peut être la première source de mint ou de lancement, mais elle ne doit pas masquer la priorité donnée aux programmes où le swap final est exécuté ;
|
||||||
- pour le trading, la première source de mint est une information de filtrage et de ciblage aussi importante que le DEX final.
|
- pour le trading, le DEX effectif, la qualité de décodage du swap et les événements de pool sont prioritaires ; la launch origin reste une information de filtrage à réintroduire après stabilisation des DEX.
|
||||||
|
|
||||||
### 4.1. Matrice de travail
|
### 4.1. Matrice de travail
|
||||||
|
|
||||||
@@ -118,31 +122,25 @@ Depuis `0.7.32`, les diagnostics distinguent explicitement les gaps littéraux d
|
|||||||
|
|
||||||
Depuis `0.7.33`, les diagnostics ajoutent une classification `pairTradingReadiness` au niveau des paires et des résumés agrégés `pairTradingReadinessSummaries`. Cette classification sépare les paires directement lisibles/tradables contre WSOL ou stable, les paires inversées avec WSOL/stable en base, les paires cross-quote nécessitant un routeur/aggregator, les paires non matérialisées en trade et les cas de quote inconnue. Elle reste purement diagnostique : elle ne modifie ni le replay, ni les `trade_events`, ni les candles.
|
Depuis `0.7.33`, les diagnostics ajoutent une classification `pairTradingReadiness` au niveau des paires et des résumés agrégés `pairTradingReadinessSummaries`. Cette classification sépare les paires directement lisibles/tradables contre WSOL ou stable, les paires inversées avec WSOL/stable en base, les paires cross-quote nécessitant un routeur/aggregator, les paires non matérialisées en trade et les cas de quote inconnue. Elle reste purement diagnostique : elle ne modifie ni le replay, ni les `trade_events`, ni les candles.
|
||||||
|
|
||||||
| Code cible | Type | Statut `0.7.29` | Prochaine action |
|
| Code cible | Type | Priorité `0.7.39+` | Prochaine action |
|
||||||
|---|---:|---|---|
|
|---|---:|---|---|
|
||||||
| `pump_fun` | Launch + bonding curve | partiel | verrouiller le rattachement mint initial -> pools migrés |
|
| `pump_swap` | AMM / swap | haute | conserver les invariants trade/candle et étendre les événements non-trade prouvés. |
|
||||||
| `pump_swap` | AMM / swap | supporté | conserver invariants trade/candle |
|
| `raydium_cpmm` | AMM | haute | vérifier corpus swap/liquidité/admin et maintenir la matérialisation trade/candle. |
|
||||||
| `raydium_cpmm` | AMM | supporté | conserver invariants trade/candle |
|
| `raydium_clmm` | CLMM | haute | vérifier corpus swap/liquidité/position et maintenir la matérialisation trade/candle. |
|
||||||
| `raydium_clmm` | CLMM | supporté | conserver invariants trade/candle |
|
| `raydium_amm_v4` | AMM legacy | haute | rechercher des paires/pools réels pour `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, valider `initialize2` et identifier les swaps. |
|
||||||
| `raydium_launchlab` | Launch surface | planifié, program id local connu | ajouter decoder/materialization dédiée |
|
| `raydium_stable_swap` | AMM legacy | moyenne | vérifier l’usage réel de `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h` et ne l’activer qu’avec corpus. |
|
||||||
| `raydium_launchpad` | Launch surface | à vérifier | ne pas inventer de program id |
|
| `meteora_dlmm` | DLMM | haute | verrouiller swaps, positions, liquidité et lifecycle. |
|
||||||
| `raydium_amm_v4` | AMM legacy | partiel | traiter après les autres Raydium avec corpus dédié |
|
| `meteora_damm_v1` | AMM legacy | haute | conserver le skip sans amounts exploitables et rechercher un corpus swap/liquidité exploitable. |
|
||||||
| `meteora_dlmm` | DLMM | supporté | verrouiller corpus et non-régression |
|
| `meteora_damm_v2` | AMM | haute | vérifier `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG`, les swaps, les configs dynamiques et les événements non-trade. |
|
||||||
| `meteora_damm_v1` | AMM legacy | partiel validé | conserver le skip explicite des swaps sans montants exploitables |
|
| `meteora_dbc` | bonding curve / DEX effectif partiel | haute | séparer ce qui relève du swap, du bonding curve et de la migration sans faux trade/candle. |
|
||||||
| `meteora_damm_v2` | AMM | partiel validé `0.7.36` | conserver les swaps sans amounts en `non_actionable_trade`; ajouter extraction de montants seulement avec preuve |
|
| `orca_whirlpools` | CLMM | haute | consolider par corpus fiable : create_pool, swap, liquidité/positions. |
|
||||||
| `meteora_dbc` | Launch / bonding curve | partiel validé `0.7.36` | conserver les swaps sans amounts en `non_actionable_trade`; étudier migration / launch origin |
|
| `fluxbeam` | AMM | moyenne | vérifier program id, corpus réel et instructions utiles. |
|
||||||
| `meteora_dlc` | À vérifier | à vérifier | confirmer surface/program id avant intégration |
|
| `dexlab` | AMM | moyenne | vérifier program id, corpus réel, swaps et liens OpenBook éventuels. |
|
||||||
| `orca_whirlpools` | CLMM | partiel | corpus fiable et validation des instructions utiles |
|
| `metaDAO` | DEX à vérifier | haute | rechercher le ou les program ids, corpus, comptes et types d’événements avant toute promotion. |
|
||||||
| `fluxbeam` | AMM | partiel | corpus fiable avant validation |
|
| `printr` | DEX à vérifier | haute | rechercher le ou les program ids, corpus, comptes et types d’événements avant toute promotion. |
|
||||||
| `dexlab` | AMM | partiel | corpus fiable avant validation |
|
| `okx_dex` | Aggregator/router | basse DEX direct | classifier sans matérialiser en trade direct avant preuve. |
|
||||||
| `bags` | Launch surface | planifié | conserver comme origine de lancement si corpus le prouve |
|
| Launch surfaces (`pump_fun`, `raydium_launchlab`, `raydium_launchpad`, `bags`, `letsbonk`, `bonk_fun`, `boop_fun`, `moonshot`, `moonit`, `believe`, `heaven`) | Launch / origine | reportée | reprendre après consolidation des DEX effectifs ; aucun `program_id` fictif. |
|
||||||
| `letsbonk` / `bonk` | Launch surface | planifié | ajouter comme origine de mint/lancement sans supposer un AMM autonome |
|
| `zora` | À vérifier | hors priorité | ne pas intégrer avant preuve de programme Solana pertinent. |
|
||||||
| `okx_dex` | Aggregator/router | planifié | classifier sans matérialiser en trade direct avant preuve |
|
|
||||||
| `boop_fun` | Launch surface | planifié | ajouter comme origine de mint/lancement et migration |
|
|
||||||
| `moonshot` / `moonit` | Launch surface | planifié | remplacer les heuristiques faibles par corpus et règles prouvées |
|
|
||||||
| `believe` | Launch surface | planifié | confirmer comptes, migration et rattachement |
|
|
||||||
| `heaven` | Launch + AMM candidat | planifié | ajouter corpus et déterminer séparation launch/swap |
|
|
||||||
| `zora` | À vérifier | à vérifier | ne pas intégrer avant preuve de programme Solana pertinent |
|
|
||||||
|
|
||||||
## 5. Base de données
|
## 5. Base de données
|
||||||
|
|
||||||
@@ -232,18 +230,32 @@ Les tests peuvent rester plus souples lorsque cela clarifie le test.
|
|||||||
|
|
||||||
## 8. Priorité immédiate
|
## 8. Priorité immédiate
|
||||||
|
|
||||||
La phase `0.7.38_token_metadata_gap_prioritization` est considérée comme close. La clôture `0.7.38-B` ajoute un registre local minimal de tokens connus : `WSOL`, `USDC`, `USDT`, `JUP`, `RAY`, `BONK`. `USDC` et `USDT` restent les seuls ajouts stable-quote ; `JUP`, `RAY` et `BONK` enrichissent seulement l’affichage metadata sans changer la classification de quote. La prochaine étape est `0.7.39_launch_surfaces`.
|
La phase `0.7.38_token_metadata_gap_prioritization` est considérée comme close. La clôture `0.7.38-B` ajoute un registre local minimal de tokens connus : `WSOL`, `USDC`, `USDT`, `JUP`, `RAY`, `BONK`. `USDC` et `USDT` restent les seuls ajouts stable-quote ; `JUP`, `RAY` et `BONK` enrichissent seulement l’affichage metadata sans changer la classification de quote.
|
||||||
|
|
||||||
|
La prochaine étape est maintenant `0.7.39_dex_first_effective_swap_surfaces`. Elle remplace la priorité précédemment donnée aux launch surfaces. L’objectif est de vérifier et consolider d’abord les vrais DEX de swap et leurs événements observables.
|
||||||
|
|
||||||
Préconditions validées avant de reprendre le codage :
|
Préconditions validées avant de reprendre le codage :
|
||||||
|
|
||||||
1. les invariants locaux restent sains : `blockingIssueCount = 0`, `actionableMissingTradeEventCount = 0`, `missingTradeEventCount = 0` ;
|
1. les invariants locaux restent sains : `blockingIssueCount = 0`, `actionableMissingTradeEventCount = 0`, `missingTradeEventCount = 0` ;
|
||||||
2. les profils `0.7.36_meteora_family_consolidation`, `0.7.37_token_metadata_catalog_enrichment` et `0.7.38_token_metadata_gap_prioritization` existent et passent sur le corpus local fourni ;
|
2. les profils `0.7.36_meteora_family_consolidation`, `0.7.37_token_metadata_catalog_enrichment` et `0.7.38_token_metadata_gap_prioritization` existent et passent sur le corpus local fourni ;
|
||||||
3. les metadata manquantes restent non bloquantes ;
|
3. les metadata manquantes restent non bloquantes ;
|
||||||
4. les `tokenMetadataGapSamples` exposent maintenant une liste de travail priorisée ;
|
4. les `tokenMetadataGapSamples` exposent une liste de travail priorisée ;
|
||||||
5. le registre local minimal contient `SOL`, `WSOL`, `USDC` et `USDT` ;
|
5. le registre local minimal contient `SOL`, `WSOL`, `USDC`, `USDT`, `JUP`, `RAY` et `BONK` ;
|
||||||
6. le backfill metadata peut traiter les tokens déjà présents en base et rafraîchir les `pair_symbol` sans recréer les objets de marché.
|
6. le backfill metadata peut traiter les tokens déjà présents en base et rafraîchir les `pair_symbol` sans recréer les objets de marché.
|
||||||
|
|
||||||
Objectif de `0.7.39` : détecter et rattacher les surfaces de lancement sans inventer de program ids, sans produire de faux trades/candles et sans confondre `launch_origin`, `pool_origin`, `dex_effective` et `migration_target`.
|
Objectifs `0.7.39+` :
|
||||||
|
|
||||||
|
- inventorier et vérifier les DEX principaux sur lesquels des swaps peuvent réellement se produire ;
|
||||||
|
- rechercher ou confirmer les `program_id` inconnus sans en inventer ;
|
||||||
|
- ajouter `metaDAO` et `Printr` comme DEX à vérifier, notamment via DEX Screener et corpus local ;
|
||||||
|
- couvrir, par DEX, les swaps, liquidités, lifecycle, fees, rewards, admin/config, burns/mints utiles et autres événements non-trade prouvés ;
|
||||||
|
- ajouter `Demo3` pour rechercher les pools/paires/signatures par DEX ou `program_id` ;
|
||||||
|
- ajouter `Demo4` pour interroger DEX Screener et comparer les résultats avec la base locale ;
|
||||||
|
- préparer des démos spécialisées pour les launch surfaces seulement après stabilisation des DEX effectifs ;
|
||||||
|
- ajouter une démo temps réel type `Demo10` avec start/stop du client WebSocket, souscriptions aux programmes DEX et écriture en base via le pipeline existant ;
|
||||||
|
- passer ensuite à la création de wallets, aux fonctions wallet et aux transferts de fonds avant toute logique de swap/trading.
|
||||||
|
|
||||||
|
Les launch surfaces restent importantes, mais elles sont reportées après la consolidation des DEX effectifs. Elles ne doivent pas générer de faux trades/candles ni de `program_id` fictif.
|
||||||
|
|
||||||
## 9. Fichiers utiles pour reprendre dans une nouvelle session
|
## 9. Fichiers utiles pour reprendre dans une nouvelle session
|
||||||
|
|
||||||
@@ -271,4 +283,4 @@ Pour reprendre rapidement le codage dans une nouvelle session, fournir au minimu
|
|||||||
- `kb_lib/src/db/dtos.rs` et `kb_lib/src/db/dtos/*` ;
|
- `kb_lib/src/db/dtos.rs` et `kb_lib/src/db/dtos/*` ;
|
||||||
- `kb_lib/src/db/queries.rs` et `kb_lib/src/db/queries/*`.
|
- `kb_lib/src/db/queries.rs` et `kb_lib/src/db/queries/*`.
|
||||||
|
|
||||||
Ajouter `kb_demo_app/src/demo_pipeline*.rs` seulement si la tâche concerne l’UI ou les diagnostics affichés.
|
Ajouter `kb_demo_app/src/demo_pipeline*.rs`, les fichiers frontend associés et les nouvelles démos (`Demo3`, `Demo4`, `Demo10`) seulement si la tâche concerne l’UI, la recherche de corpus, les diagnostics affichés ou le watcher temps réel.
|
||||||
|
|||||||
317
ROADMAP.md
317
ROADMAP.md
@@ -942,195 +942,182 @@ Réalisé :
|
|||||||
- validation locale confirmée avec `validationPassed = true`, `blockingIssueCount = 0`, `missingTradeEventCount = 0`, `decodedTradeCandidateWithoutTradeEventCount = 0` ;
|
- validation locale confirmée avec `validationPassed = true`, `blockingIssueCount = 0`, `missingTradeEventCount = 0`, `decodedTradeCandidateWithoutTradeEventCount = 0` ;
|
||||||
- les samples permettent de sélectionner les prochains mints à enrichir via registre local, payloads DEX, Token-2022, Metaplex ou backfill HTTP.
|
- les samples permettent de sélectionner les prochains mints à enrichir via registre local, payloads DEX, Token-2022, Metaplex ou backfill HTTP.
|
||||||
|
|
||||||
Décision : `0.7.38` est clos. La clôture `0.7.38-B` conserve la logique de stable quotes limitée à `USDC`/`USDT` et ajoute un registre metadata local pour `JUP`, `RAY` et `BONK` sans les classer automatiquement comme quotes. La suite de développement commence à `0.7.39` avec les launch surfaces.
|
Décision : `0.7.38` est clos. La clôture `0.7.38-B` conserve la logique de stable quotes limitée à `USDC`/`USDT` et ajoute un registre metadata local pour `JUP`, `RAY` et `BONK` sans les classer automatiquement comme quotes. La suite de développement commence à `0.7.39` avec une priorité DEX-first : consolider les DEX effectifs de swap avant de revenir aux launch surfaces.
|
||||||
|
|
||||||
### 6.071. Version `0.7.39` — Launch surfaces : LaunchLab, LetsBonk, Bags, Moonshot/Moonit, Boop.fun, Believe
|
### 6.071. Version `0.7.39` — Réorientation DEX-first et inventaire des DEX effectifs
|
||||||
Objectif : détecter la première source de mint/lancement des tokens même lorsque le swap final se fait ailleurs.
|
Objectif : remplacer la priorité précédemment donnée aux launch surfaces par une consolidation des vrais DEX sur lesquels les swaps et événements de marché sont exécutés.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- ajouter ou stabiliser `raydium_launchlab` / `raydium_launchpad`,
|
- modifier la matrice DEX pour distinguer explicitement : `dex_effective`, `aggregator/router`, `launch_surface`, `to_verify` ;
|
||||||
- ajouter `letsbonk` / `bonk_fun` comme surface d’origine rattachée à LaunchLab/Raydium si le corpus le prouve,
|
- vérifier les DEX de swap principaux déjà connus : `pump_swap`, `raydium_cpmm`, `raydium_clmm`, `raydium_amm_v4`, `raydium_stable_swap`, `meteora_dlmm`, `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc`, `orca_whirlpools`, `fluxbeam`, `dexlab` ;
|
||||||
- ajouter `boop_fun` comme surface d’origine et suivre ses migrations,
|
- ajouter `metaDAO` et `Printr` comme entrées `to_verify` dans la matrice, sans `program_id` tant qu’ils ne sont pas prouvés ;
|
||||||
- consolider `moonshot` / `moonit` avec corpus au lieu de simples heuristiques faibles,
|
- rechercher ou confirmer les `program_id` inconnus depuis les corpus locaux, les protocol candidates, DEX Screener, les explorateurs et les transactions résolues ;
|
||||||
- consolider `bags` comme surface d’origine, notamment lorsque le token passe par Meteora DBC/DAMM,
|
- ne promouvoir aucune entrée vers `partial` ou `supported` sans corpus transactionnel vérifiable ;
|
||||||
- ajouter `believe` comme surface d’origine associée à Meteora DBC si les comptes/authorities le prouvent,
|
- conserver les invariants `0.7.36` à `0.7.38` : aucun faux trade, aucune fausse candle, aucun événement non price-action transformé en trade/candle.
|
||||||
- distinguer `launch_origin`, `pool_origin`, `dex_effective` et `migration_target`,
|
|
||||||
- rattacher les launch origins aux pools et paires lorsque les comptes permettent un matching fiable,
|
|
||||||
- exposer les origins dans les diagnostics et l’UI d’inspection.
|
|
||||||
|
|
||||||
### 6.072. Version `0.7.39` — Heaven : corpus, launch et AMM
|
Résultat attendu : une matrice DEX réorientée vers les surfaces de swap effectives, avec les launch surfaces explicitement reportées.
|
||||||
Objectif : ajouter Heaven sans le classer trop tôt comme simple DEX ou simple launchpad.
|
|
||||||
|
### 6.072. Version `0.7.40` — Raydium effectif : AMM v4, Stable Swap, CPMM, CLMM
|
||||||
|
Objectif : consolider la famille Raydium côté DEX effectifs avant les launch surfaces Raydium.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- vérifier le ou les programmes Heaven réellement observés sur mainnet,
|
- vérifier `raydium_cpmm` et `raydium_clmm` comme références déjà supportées ;
|
||||||
- constituer un corpus local de mints, pools et swaps Heaven,
|
- rechercher des pools réellement rattachés au programme AMM v4 `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` ;
|
||||||
- séparer les événements de lancement des événements de swap,
|
- vérifier l’usage réel de `raydium_stable_swap` et du programme `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h` ;
|
||||||
- ajouter les decoded events, launch origins, pool/pair/listing et trade events seulement lorsque les instructions sont prouvées,
|
- distinguer clairement `raydium_amm_v4`, `raydium_cpmm`, `raydium_clmm`, `raydium_router`, `raydium_stable_swap`, `raydium_launchlab` et `raydium_launchpad` ;
|
||||||
- documenter les limites si le corpus ne permet pas encore de matérialiser tous les événements,
|
- identifier les instructions swap, initialize/create pool, liquidité, fees/admin réellement observées ;
|
||||||
- vérifier que Heaven ne crée pas de candles invalides en cas d’événement de launch non pricé.
|
- ajouter des requêtes diagnostics par `program_id`, `accounts_json`, `data_json`, signature et pool address ;
|
||||||
|
- documenter les limites si le corpus Raydium legacy reste faible.
|
||||||
|
|
||||||
### 6.073. Version `0.7.40` — Orca / FluxBeam / DexLab : corpus et validation ciblée
|
### 6.073. Version `0.7.41` — Meteora effectif : DLMM, DAMM v1/v2, DBC
|
||||||
Objectif : consolider les connecteurs déjà présents à partir de corpus locaux vérifiables.
|
Objectif : compléter la famille Meteora en couvrant les événements réellement utiles au DEX effectif.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- constituer des corpus locaux pour `Orca Whirlpools`, `FluxBeam` et `DexLab`,
|
- conserver la validation `0.7.36` : les swaps DAMM v2 / DBC sans amounts fiables restent `non_actionable_trade` ;
|
||||||
- vérifier les `program_id`, comptes, préfixes `data_json` et familles d’instructions utiles,
|
- vérifier `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` et les autres programmes Meteora dans le corpus local ;
|
||||||
- stabiliser les événements `create_pool`, `swap` et liquidité réellement observés,
|
- consolider `meteora_dlmm` pour swaps, positions, add/remove liquidity, lifecycle et non-trade events ;
|
||||||
- alimenter les mêmes tables métier et diagnostics que les connecteurs déjà validés,
|
- consolider `meteora_damm_v1` et `meteora_damm_v2` pour pools, swaps exploitables, configs dynamiques, fees/admin ;
|
||||||
- marquer explicitement les variantes partiellement supportées ou heuristiques,
|
- clarifier la part `launch/bonding_curve` et la part `dex_effective` de `meteora_dbc` ;
|
||||||
- rejouer les corpus plusieurs fois pour vérifier l’idempotence et l’absence de trades/candles invalides.
|
- éviter tout trade/candle artificiel lorsque les montants ou prix ne sont pas prouvés.
|
||||||
|
|
||||||
### 6.074. Version `0.7.41` — Raydium AMM v4 legacy : corpus et validation ciblée
|
### 6.074. Version `0.7.42` — Autres DEX effectifs : Orca, FluxBeam, DexLab, metaDAO, Printr
|
||||||
Objectif : traiter le vrai Raydium AMM v4 historique après les autres Raydium, afin de l’isoler de `raydium_cpmm`, `raydium_clmm` et des labels Raydium génériques.
|
Objectif : consolider les DEX non-Raydium/Meteora et intégrer les DEX récemment observés comme candidats vérifiables.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- rechercher des pools réellement rattachés au programme `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`,
|
- constituer des corpus locaux pour `orca_whirlpools`, `fluxbeam` et `dexlab` ;
|
||||||
- constituer un petit corpus local de signatures/pools AMM v4 fiables,
|
- vérifier les `program_id`, comptes, préfixes `data_json` et familles d’instructions utiles ;
|
||||||
- vérifier que les adresses issues d’explorateurs ne sont pas seulement catégorisées globalement comme `Raydium`,
|
- stabiliser les événements `create_pool`, `swap`, liquidité, positions et admin lorsque prouvés ;
|
||||||
- ajouter des requêtes de diagnostic par `program_id`, `accounts_json` et préfixe `data_json`,
|
- ajouter `metaDAO` et `Printr` en `to_verify` avec recherche explicite de program ids, signatures, comptes et pools ;
|
||||||
- valider `initialize2` et identifier les instructions de swap AMM v4 à supporter si elles apparaissent dans le corpus,
|
- ne pas confondre source externe de découverte et preuve on-chain ;
|
||||||
- renommer/stabiliser les fonctions internes autour de `raydium_amm_v4` pour éviter l’ambiguïté avec `raydium_cpmm` et `raydium_clmm`,
|
- marquer explicitement les variantes partiellement supportées ou heuristiques.
|
||||||
- documenter les limites connues si le corpus AMM v4 reste faible.
|
|
||||||
|
|
||||||
### 6.075. Version `0.7.42` — Validation DEX v1 consolidée
|
### 6.075. Version `0.7.43` — Couverture événementielle DEX : swap, liquidité, fees, rewards, admin, burns
|
||||||
Objectif : rejouer tous les DEX et launch surfaces supportés et valider les invariants du pipeline complet.
|
Objectif : s’assurer que chaque DEX effectif expose les événements utiles au scoring et au risque sans polluer les trades/candles.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- rejouer des bases neuves couvrant tous les connecteurs DEX supportés,
|
- vérifier par DEX la couverture `swap` / `tradeCandidate` / `candleCandidate` ;
|
||||||
- vérifier les compteurs globaux et par DEX : decoded events, trade events, liquidity events, lifecycle events, fee events, reward events, admin events, candles et analytic signals,
|
- vérifier par DEX la couverture liquidité : add/remove/increase/decrease/open/close position ;
|
||||||
- contrôler que chaque famille d’événements alimente uniquement les tables métier prévues,
|
- vérifier par DEX les événements lifecycle : create/init/migrate/pause/resume/close ;
|
||||||
- vérifier les diagnostics bloquants et les samples d’anomalie,
|
- vérifier par DEX les fees, rewards, creator fees, protocol fees et admin/config ;
|
||||||
- documenter les corpus utilisés pour chaque DEX/surface,
|
- vérifier les burns/mints utiles au suivi token/pool sans les transformer en price-action ;
|
||||||
- conserver une matrice de support par DEX, variante, instruction et type d’événement,
|
- matérialiser uniquement les événements prouvés dans les tables dédiées ;
|
||||||
|
- ajouter des compteurs et samples diagnostics par DEX et par type d’événement ;
|
||||||
|
- conserver l’invariant : aucun fee/reward/admin/liquidity/lifecycle/burn non price-action ne produit de trade, metric ou candle.
|
||||||
|
|
||||||
|
### 6.076. Version `0.7.44` — `kb_demo_app` Demo3 : recherche de paires/pools par DEX ou program id
|
||||||
|
Objectif : ajouter une fenêtre ou vue de démonstration dédiée à la constitution de corpus par DEX.
|
||||||
|
|
||||||
|
À faire :
|
||||||
|
|
||||||
|
- ajouter une `Demo3` dans `kb_demo_app` ;
|
||||||
|
- permettre la saisie d’un `program_id`, d’un `dex_code`, d’un `pool_address`, d’un `pair_id` ou d’un token mint ;
|
||||||
|
- rechercher dans la base locale les transactions, instructions, decoded events, pools, paires, listings et candidates associés ;
|
||||||
|
- fournir des presets pour les programmes à vérifier, par exemple `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`, `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` ;
|
||||||
|
- afficher les signatures candidates à backfill/replay ;
|
||||||
|
- garder `kb_demo_app` comme façade UI : toute requête métier doit rester dans `kb_lib`.
|
||||||
|
|
||||||
|
### 6.077. Version `0.7.45` — `kb_demo_app` Demo4 : DEX Screener et sources externes de découverte
|
||||||
|
Objectif : utiliser des sources externes comme aides à la découverte de corpus sans les traiter comme vérité métier.
|
||||||
|
|
||||||
|
À faire :
|
||||||
|
|
||||||
|
- ajouter une `Demo4` pour interroger DEX Screener ou une source équivalente ;
|
||||||
|
- rechercher des paires par token mint, chain, DEX name, pool address ou program id lorsque disponible ;
|
||||||
|
- comparer les résultats externes avec les objets locaux : tokens, pools, pairs, listings, decoded events ;
|
||||||
|
- afficher les écarts : paire externe absente localement, pool local sans source externe, DEX label ambigu, program id manquant ;
|
||||||
|
- permettre de copier les signatures/adresses candidates pour backfill ;
|
||||||
|
- ne jamais promouvoir automatiquement un DEX, un `program_id` ou une paire sur la seule base d’une réponse externe.
|
||||||
|
|
||||||
|
### 6.078. Version `0.7.46` — Démos spécialisées launch surfaces après DEX effectifs
|
||||||
|
Objectif : préparer des vues spécialisées pour les launch surfaces, mais seulement après stabilisation des DEX effectifs.
|
||||||
|
|
||||||
|
À faire plus tard :
|
||||||
|
|
||||||
|
- ajouter des démos dédiées à `pump_fun`, `raydium_launchpad` / `raydium_launchlab`, `believe`, `bags`, `moonshot` / `moonit`, `boop_fun`, `letsbonk` / `bonk_fun`, `heaven` ;
|
||||||
|
- distinguer `launch_origin`, `pool_origin`, `dex_effective` et `migration_target` ;
|
||||||
|
- rattacher les launch origins aux pools et paires uniquement lorsque les comptes permettent un matching fiable ;
|
||||||
|
- exposer les origins dans les diagnostics et l’UI d’inspection ;
|
||||||
|
- maintenir l’interdiction de faux program ids, faux trades et fausses candles.
|
||||||
|
|
||||||
|
### 6.079. Version `0.7.47` — `kb_demo_app` Demo10 : watcher WebSocket live DEX
|
||||||
|
Objectif : valider le passage du replay/backfill vers l’observation temps réel contrôlée.
|
||||||
|
|
||||||
|
À faire :
|
||||||
|
|
||||||
|
- ajouter une démo temps réel type `Demo10` avec bouton `start` / `stop` ;
|
||||||
|
- permettre de sélectionner les endpoints WS/HTTP et les DEX/program ids à souscrire ;
|
||||||
|
- lancer le client WebSocket existant sans refactorer inutilement `ws_client.rs` / `ws_manager.rs` ;
|
||||||
|
- effectuer les `logsSubscribe`, `programSubscribe` ou `accountSubscribe` nécessaires selon le DEX ;
|
||||||
|
- détecter en temps réel mints, swaps, liquidités et autres événements utiles ;
|
||||||
|
- écrire en base via le pipeline existant : observations, transactions résolues, decoded events, pools/pairs/listings, trade events, candles et non-trade events ;
|
||||||
|
- afficher les compteurs live, erreurs, subscriptions actives et derniers objets persistés ;
|
||||||
|
- prévoir un arrêt propre avec unsubscribe avant close.
|
||||||
|
|
||||||
|
### 6.080. Version `0.7.48` — Validation DEX v1 consolidée
|
||||||
|
Objectif : rejouer tous les DEX effectifs supportés et valider les invariants du pipeline complet avant de revenir aux launch surfaces ou à l’analyse `0.8.x`.
|
||||||
|
|
||||||
|
À faire :
|
||||||
|
|
||||||
|
- rejouer des bases neuves couvrant tous les connecteurs DEX supportés ;
|
||||||
|
- vérifier les compteurs globaux et par DEX : decoded events, trade events, liquidity events, lifecycle events, fee events, reward events, admin events, burns/mints utiles, candles et analytic signals ;
|
||||||
|
- contrôler que chaque famille d’événements alimente uniquement les tables métier prévues ;
|
||||||
|
- vérifier les diagnostics bloquants et les samples d’anomalie ;
|
||||||
|
- documenter les corpus utilisés pour chaque DEX/surface ;
|
||||||
|
- conserver une matrice de support par DEX, variante, instruction et type d’événement ;
|
||||||
- verrouiller les invariants avant d’ouvrir l’analyse `0.8.x`.
|
- verrouiller les invariants avant d’ouvrir l’analyse `0.8.x`.
|
||||||
|
|
||||||
### 6.076. Version `0.7.43` — `kb_demo_app` : overlays analytiques
|
### 6.081. Version `0.8.x` — Analyse et filtrage
|
||||||
Objectif : rendre visibles les signaux analytiques directement sur les graphes et vues de marché.
|
|
||||||
|
|
||||||
À faire :
|
|
||||||
|
|
||||||
- afficher les signaux analytiques par bucket au-dessus ou autour des candles,
|
|
||||||
- ajouter des marqueurs pour `first_trade_seen`, `trade_burst_60s`, `buy_sell_imbalance_60s`, `price_jump_up_60s`, `price_jump_down_60s` et `volume_spike_60s`,
|
|
||||||
- permettre le filtrage par type de signal et par sévérité,
|
|
||||||
- afficher un panneau latéral listant les signaux liés à une paire et à un timeframe,
|
|
||||||
- préparer l’extension future vers Ichimoku, Kumo, projections ABCD et égalités temps/prix sans les mélanger au pipeline de décodage DEX.
|
|
||||||
|
|
||||||
### 6.077. Version `0.7.44` — `kb_demo_app` : vues consolidées token / pair / pool
|
|
||||||
Objectif : fournir une lecture métier plus confortable du modèle `0.7.x`.
|
|
||||||
|
|
||||||
À faire :
|
|
||||||
|
|
||||||
- ajouter une fiche token avec mint, programme token, metadata, pools, paires et historique de découverte,
|
|
||||||
- ajouter une fiche paire avec base/quote, DEX, pool, métriques, candles, signaux et derniers trades,
|
|
||||||
- ajouter une fiche pool avec composition, vaults, origine, première signature vue, programme DEX et statut de décodage,
|
|
||||||
- relier dans l’UI les launch origins, pool origins, wallets observés, holdings observés, événements de liquidité, lifecycle, fees, rewards, admin, candles et analytic signals,
|
|
||||||
- préparer une navigation transversale entre objets techniques et objets métier,
|
|
||||||
- rendre explicites les cas `tradeCount = null`, `lastPriceQuotePerBase = null`, tokens non enrichis et événements conservés uniquement pour analyse.
|
|
||||||
|
|
||||||
### 6.078. Version `0.7.45` — Finition UI `0.7.x`
|
|
||||||
Objectif : stabiliser la couche desktop de validation avant l’ouverture de `0.8.x`.
|
|
||||||
|
|
||||||
À faire :
|
|
||||||
|
|
||||||
- consolider les vues ajoutées dans `kb_demo_app`,
|
|
||||||
- améliorer la navigation, les filtres et la pagination,
|
|
||||||
- ajouter les derniers raffinements de confort et de lisibilité,
|
|
||||||
- préparer une base UI suffisamment stable pour la future phase d’analyse et filtrage `0.8.x`,
|
|
||||||
- vérifier que les commandes Tauri restent de simples façades vers `kb_lib`.
|
|
||||||
|
|
||||||
### 6.079. Version `0.7.x` — Couverture DEX v1
|
|
||||||
Objectif : structurer les connecteurs DEX autour d’un pipeline complet de résolution, décodage, normalisation métier et classification des événements non-trade.
|
|
||||||
|
|
||||||
Protocoles et surfaces cibles :
|
|
||||||
|
|
||||||
- Pump.fun,
|
|
||||||
- PumpSwap,
|
|
||||||
- Raydium CPMM,
|
|
||||||
- Raydium CLMM,
|
|
||||||
- Raydium LaunchLab / Launchpad,
|
|
||||||
- Raydium AMM v4 legacy,
|
|
||||||
- Meteora DBC,
|
|
||||||
- Meteora DAMM v1,
|
|
||||||
- Meteora DAMM v2,
|
|
||||||
- Meteora DLMM,
|
|
||||||
- Orca Whirlpools,
|
|
||||||
- FluxBeam,
|
|
||||||
- DexLab,
|
|
||||||
- Bags,
|
|
||||||
- LetsBonk / Bonk.fun,
|
|
||||||
- Boop.fun,
|
|
||||||
- Moonshot / Moonit,
|
|
||||||
- Believe,
|
|
||||||
- Heaven.
|
|
||||||
|
|
||||||
Hors périmètre immédiat :
|
|
||||||
|
|
||||||
- `zora_solana`, tant qu’aucun programme Solana pertinent et exploitable n’est prouvé.
|
|
||||||
|
|
||||||
Résultat attendu :
|
|
||||||
|
|
||||||
- identification fiable des programmes et versions,
|
|
||||||
- résolution des signatures pertinentes,
|
|
||||||
- décodage des transactions utiles,
|
|
||||||
- conservation des transactions inconnues ou candidates sans perte d’information,
|
|
||||||
- création d’objets métier riches pour tokens, pools, paires, listings, participants, origins et holdings observés,
|
|
||||||
- distinction claire entre première source de mint, launch origin, pool origin, DEX effectif et migration target,
|
|
||||||
- enrichissement metadata des tokens découverts,
|
|
||||||
- séparation stricte entre événements candle/trade et événements utiles seulement à l’analyse,
|
|
||||||
- matérialisation progressive des événements non-trade dans des tables métier dédiées,
|
|
||||||
- préparation d’une détection temps réel hybride et d’un backfill ciblé compatible avec les mêmes objets métier,
|
|
||||||
- préparation d’agrégats DEX plus riches, de candles/OHLCV et d’une UI d’inspection du pipeline `0.7.x`.
|
|
||||||
|
|
||||||
### 6.080. Version `0.8.x` — Analyse et filtrage
|
|
||||||
Objectif : transformer les événements bruts en signaux exploitables.
|
Objectif : transformer les événements bruts en signaux exploitables.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- agrégation des métriques,
|
- agrégation des métriques ;
|
||||||
- règles de filtrage,
|
- règles de filtrage ;
|
||||||
- exclusions des tokens non tradables,
|
- exclusions des tokens non tradables ;
|
||||||
- statistiques de comportement,
|
- statistiques de comportement ;
|
||||||
- premiers patterns,
|
- premiers patterns ;
|
||||||
- enrichissement des signaux analytiques préparés en fin de `0.7.x`,
|
- enrichissement des signaux analytiques préparés en fin de `0.7.x` ;
|
||||||
- indicateurs graphiques optionnels comme Ichimoku / Kumo,
|
- indicateurs graphiques optionnels comme Ichimoku / Kumo ;
|
||||||
- outils de sélection manuelle de points ABC et projection d’un point D selon des règles temps/prix explicites,
|
- outils de sélection manuelle de points ABC et projection d’un point D selon des règles temps/prix explicites ;
|
||||||
- séparation stricte entre signaux analytiques observés, projections hypothétiques et décisions de trading.
|
- séparation stricte entre signaux analytiques observés, projections hypothétiques et décisions de trading.
|
||||||
|
|
||||||
### 6.081. Version `1.x.y` — Wallets et swap préparatoire
|
### 6.082. Version `1.x.y` — Wallets, comptes et transferts
|
||||||
Objectif : préparer la couche d’action.
|
Objectif : préparer la couche d’action sans encore brancher l’achat/vente automatique.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- gestion du répertoire wallets,
|
- gestion du répertoire wallets ;
|
||||||
- chargement sécurisé des keypairs,
|
- création de wallet/keypair ;
|
||||||
- abstraction wallet,
|
- chargement sécurisé des keypairs ;
|
||||||
- préparation d’ordres et de swaps,
|
- inspection des informations wallet ;
|
||||||
- simulation et garde-fous.
|
- transfert de fonds depuis cette wallet vers un autre account ;
|
||||||
|
- garde-fous d’affichage, confirmation et simulation ;
|
||||||
|
- préparation d’ordres et de swaps seulement après stabilisation des transferts de base.
|
||||||
|
|
||||||
### 6.082. Version `2.x.y` — Trading semi-automatisé
|
### 6.083. Version `2.x.y` — Trading semi-automatisé
|
||||||
Objectif : brancher l’analyse à l’action tout en gardant des garde-fous explicites.
|
Objectif : brancher l’analyse à l’action tout en gardant des garde-fous explicites.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- scénarios d’achat/vente,
|
- scénarios d’achat/vente ;
|
||||||
- règles d’entrée/sortie,
|
- règles d’entrée/sortie ;
|
||||||
- limites de risque,
|
- limites de risque ;
|
||||||
- confirmations explicites ou semi-automatiques,
|
- confirmations explicites ou semi-automatiques ;
|
||||||
- journaux d’exécution.
|
- journaux d’exécution.
|
||||||
|
|
||||||
### 6.083. Version `3.x.y` — Yellowstone gRPC
|
### 6.084. Version `3.x.y` — Yellowstone gRPC
|
||||||
Objectif : ajouter le connecteur gRPC dédié.
|
Objectif : ajouter le connecteur gRPC dédié.
|
||||||
|
|
||||||
À faire :
|
À faire :
|
||||||
|
|
||||||
- `GrpcClient` basé sur `yellowstone-grpc-client`,
|
- `GrpcClient` basé sur `yellowstone-grpc-client` ;
|
||||||
- adaptation du pipeline d’événements,
|
- adaptation du pipeline d’événements ;
|
||||||
- coexistence HTTP / WS / gRPC,
|
- coexistence HTTP / WS / gRPC ;
|
||||||
- politique de répartition par source.
|
- politique de répartition par source.
|
||||||
|
|
||||||
## 7. Organisation des modules ciblés
|
## 7. Organisation des modules ciblés
|
||||||
@@ -1186,6 +1173,9 @@ Responsabilités cibles :
|
|||||||
- réception des événements venant de `kb_lib`,
|
- réception des événements venant de `kb_lib`,
|
||||||
- fenêtres de démonstration / diagnostic isolées,
|
- fenêtres de démonstration / diagnostic isolées,
|
||||||
- inspection du pipeline persisté,
|
- inspection du pipeline persisté,
|
||||||
|
- `Demo3` pour la recherche de paires/pools par DEX ou `program_id`,
|
||||||
|
- `Demo4` pour les requêtes DEX Screener et la comparaison avec la base locale,
|
||||||
|
- `Demo10` pour le watcher WebSocket live DEX avec start/stop,
|
||||||
- affichage candles et futurs overlays analytiques.
|
- affichage candles et futurs overlays analytiques.
|
||||||
|
|
||||||
`kb_demo_app` ne doit pas contenir de logique métier DEX profonde.
|
`kb_demo_app` ne doit pas contenir de logique métier DEX profonde.
|
||||||
@@ -1253,7 +1243,7 @@ Le projet doit maintenir au minimum :
|
|||||||
|
|
||||||
## 12. Priorité immédiate
|
## 12. Priorité immédiate
|
||||||
|
|
||||||
La priorité immédiate est `0.7.39_launch_surfaces` : détecter et rattacher les origines de lancement sans casser les invariants `0.7.36` à `0.7.38`.
|
La priorité immédiate après `0.7.38-B` est `0.7.39_dex_first_effective_swap_surfaces`. La phase launch surfaces est volontairement reportée : elle sera reprise après consolidation des DEX effectifs et des outils de constitution de corpus.
|
||||||
|
|
||||||
Préconditions validées avant `0.7.39` :
|
Préconditions validées avant `0.7.39` :
|
||||||
|
|
||||||
@@ -1261,13 +1251,28 @@ Préconditions validées avant `0.7.39` :
|
|||||||
2. validation `0.7.37` acquise : compteurs metadata/catalog exposés, backfill metadata idempotent, `pair_symbol` rafraîchissables, metadata manquantes non bloquantes ;
|
2. validation `0.7.37` acquise : compteurs metadata/catalog exposés, backfill metadata idempotent, `pair_symbol` rafraîchissables, metadata manquantes non bloquantes ;
|
||||||
3. validation `0.7.38` acquise : `tokenMetadataGapSamples` priorisés, Demo Pipeline 2 raccordé, `validationPassed = true`, `blockingIssueCount = 0`, registre local `WSOL`/`USDC`/`USDT`/`JUP`/`RAY`/`BONK` disponible ;
|
3. validation `0.7.38` acquise : `tokenMetadataGapSamples` priorisés, Demo Pipeline 2 raccordé, `validationPassed = true`, `blockingIssueCount = 0`, registre local `WSOL`/`USDC`/`USDT`/`JUP`/`RAY`/`BONK` disponible ;
|
||||||
4. registre local minimal disponible : `SOL`, `WSOL`, `USDC`, `USDT` ;
|
4. registre local minimal disponible : `SOL`, `WSOL`, `USDC`, `USDT` ;
|
||||||
5. les diagnostics locaux restent l’outil de vérité pour décider si une surface peut passer de `planned` à `partial` ou `supported`.
|
5. les diagnostics locaux restent l’outil de vérité pour décider si un DEX peut passer de `planned` ou `to_verify` à `partial` ou `supported`.
|
||||||
|
|
||||||
Ordre de travail recommandé pour `0.7.39` :
|
Ordre de travail recommandé pour `0.7.39+` :
|
||||||
|
|
||||||
1. scanner `launch_origin.rs`, `pool_origin.rs`, `protocol_candidate_recording.rs`, `dex_support_matrix.rs`, `transaction_classification.rs`, `dex_decode.rs` et `dex_detect.rs` ;
|
1. scanner `dex_support_matrix.rs`, `dex.rs`, `dex/*.rs`, `dex_decode.rs`, `dex_detect.rs`, `trade_aggregation.rs`, `local_pipeline_validation.rs`, `local_pipeline_diagnostics.rs`, `transaction_classification.rs` et `protocol_candidate_recording.rs` ;
|
||||||
2. identifier les surfaces candidates déjà présentes dans la matrice : Raydium LaunchLab/Launchpad, LetsBonk/Bonk.fun, Bags, Moonshot/Moonit, Boop.fun et Believe ;
|
2. produire un état des DEX effectifs déjà couverts, partiels, à vérifier ou absents ;
|
||||||
3. ne promouvoir une surface que si le corpus prouve le program id, les comptes/authorities et la migration vers le DEX effectif ;
|
3. ajouter `metaDAO` et `Printr` comme DEX `to_verify` sans `program_id` inventé ;
|
||||||
4. distinguer explicitement `launch_origin`, `pool_origin`, `dex_effective` et `migration_target` ;
|
4. vérifier les DEX principaux de swap : PumpSwap, Raydium CPMM/CLMM/AMM v4/Stable Swap, Meteora DLMM/DAMM/DBC, Orca Whirlpools, FluxBeam, DexLab ;
|
||||||
5. exposer les origins dans les diagnostics et l’UI d’inspection ;
|
5. rechercher des corpus par `program_id`, pair/pool address, signature et token mint ;
|
||||||
6. conserver les garde-fous : pas de faux trade, pas de fausse candle, pas de program id inventé, pas de metadata manquante bloquante.
|
6. ajouter `Demo3` pour rechercher localement les paires/pools/signatures par DEX ou `program_id` ;
|
||||||
|
7. ajouter `Demo4` pour interroger DEX Screener ou sources externes et comparer avec la base locale sans promotion automatique ;
|
||||||
|
8. compléter la couverture par DEX des swaps, liquidités, lifecycle, fees, rewards, admin/config, burns/mints utiles ;
|
||||||
|
9. ajouter ensuite `Demo10` pour le watcher WebSocket live DEX avec start/stop, subscribe/unsubscribe et écriture en base via le pipeline existant ;
|
||||||
|
10. reprendre seulement après cela les launch surfaces : Raydium LaunchLab/Launchpad, LetsBonk/Bonk.fun, Bags, Moonshot/Moonit, Boop.fun, Believe, Heaven ;
|
||||||
|
11. passer ensuite à la couche wallet : création de wallet/keypair, inspection et transfert de fonds vers un autre account.
|
||||||
|
|
||||||
|
Garde-fous constants :
|
||||||
|
|
||||||
|
- pas de faux trade ;
|
||||||
|
- pas de fausse candle ;
|
||||||
|
- pas de `program_id` fictif ;
|
||||||
|
- pas de promotion d’un DEX sans corpus transactionnel ;
|
||||||
|
- pas de logique métier DEX profonde dans `kb_demo_app` ;
|
||||||
|
- pas de metadata manquante bloquante ;
|
||||||
|
- pas de refactor réseau inutile tant que les clients HTTP/WS existants suffisent.
|
||||||
|
|||||||
@@ -166,7 +166,8 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="demoPipeline2ValidationProfileSelect" class="form-label">Validation profile</label>
|
<label for="demoPipeline2ValidationProfileSelect" class="form-label">Validation profile</label>
|
||||||
<select id="demoPipeline2ValidationProfileSelect" class="form-select">
|
<select id="demoPipeline2ValidationProfileSelect" class="form-select">
|
||||||
<option value="0.7.38_token_metadata_gap_prioritization" selected>0.7.38 — token metadata gap prioritization</option>
|
<option value="0.7.39_launch_surface_origin_baseline" selected>0.7.39 — launch surface origin baseline</option>
|
||||||
|
<option value="0.7.38_token_metadata_gap_prioritization">0.7.38 — token metadata gap prioritization</option>
|
||||||
<option value="0.7.37_token_metadata_catalog_enrichment">0.7.37 — token metadata/catalog enrichment</option>
|
<option value="0.7.37_token_metadata_catalog_enrichment">0.7.37 — token metadata/catalog enrichment</option>
|
||||||
<option value="0.7.36_meteora_family_consolidation">0.7.36 — Meteora family consolidation</option>
|
<option value="0.7.36_meteora_family_consolidation">0.7.36 — Meteora family consolidation</option>
|
||||||
<option value="0.7.35_non_trade_fee_reward_admin">0.7.35 — non-trade fee/reward admin</option>
|
<option value="0.7.35_non_trade_fee_reward_admin">0.7.35 — non-trade fee/reward admin</option>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local launch-origin diagnostic sample for the UI.
|
||||||
|
*/
|
||||||
|
export type DemoPipeline2LocalLaunchOriginDiagnosticSample = {
|
||||||
|
/**
|
||||||
|
* Launch attribution id.
|
||||||
|
*/
|
||||||
|
launchAttributionId: number,
|
||||||
|
/**
|
||||||
|
* Launch surface code.
|
||||||
|
*/
|
||||||
|
launchSurfaceCode: string,
|
||||||
|
/**
|
||||||
|
* Launch surface display name.
|
||||||
|
*/
|
||||||
|
launchSurfaceName: string,
|
||||||
|
/**
|
||||||
|
* Transaction signature.
|
||||||
|
*/
|
||||||
|
transactionSignature: string,
|
||||||
|
/**
|
||||||
|
* Decoded event id.
|
||||||
|
*/
|
||||||
|
decodedEventId: number,
|
||||||
|
/**
|
||||||
|
* Effective protocol recorded on the decoded event.
|
||||||
|
*/
|
||||||
|
protocolName: string,
|
||||||
|
/**
|
||||||
|
* Match kind used for attribution.
|
||||||
|
*/
|
||||||
|
matchKind: string,
|
||||||
|
/**
|
||||||
|
* Matched key value.
|
||||||
|
*/
|
||||||
|
matchedValue: string,
|
||||||
|
/**
|
||||||
|
* Optional pool id.
|
||||||
|
*/
|
||||||
|
poolId: number | null,
|
||||||
|
/**
|
||||||
|
* Optional pool address.
|
||||||
|
*/
|
||||||
|
poolAddress: string | null,
|
||||||
|
/**
|
||||||
|
* Optional pair id.
|
||||||
|
*/
|
||||||
|
pairId: number | null,
|
||||||
|
/**
|
||||||
|
* Optional pair symbol.
|
||||||
|
*/
|
||||||
|
pairSymbol: string | null, };
|
||||||
@@ -3,6 +3,7 @@ import type { DemoPipeline2LocalDecodedEventDiagnosticSummary } from "./DemoPipe
|
|||||||
import type { DemoPipeline2LocalDexDiagnosticSummary } from "./DemoPipeline2LocalDexDiagnosticSummary";
|
import type { DemoPipeline2LocalDexDiagnosticSummary } from "./DemoPipeline2LocalDexDiagnosticSummary";
|
||||||
import type { DemoPipeline2LocalDuplicateDecodedEventTradeDiagnosticSample } from "./DemoPipeline2LocalDuplicateDecodedEventTradeDiagnosticSample";
|
import type { DemoPipeline2LocalDuplicateDecodedEventTradeDiagnosticSample } from "./DemoPipeline2LocalDuplicateDecodedEventTradeDiagnosticSample";
|
||||||
import type { DemoPipeline2LocalEventClassificationDiagnosticSummary } from "./DemoPipeline2LocalEventClassificationDiagnosticSummary";
|
import type { DemoPipeline2LocalEventClassificationDiagnosticSummary } from "./DemoPipeline2LocalEventClassificationDiagnosticSummary";
|
||||||
|
import type { DemoPipeline2LocalLaunchOriginDiagnosticSample } from "./DemoPipeline2LocalLaunchOriginDiagnosticSample";
|
||||||
import type { DemoPipeline2LocalMissingTradeEventDiagnosticSample } from "./DemoPipeline2LocalMissingTradeEventDiagnosticSample";
|
import type { DemoPipeline2LocalMissingTradeEventDiagnosticSample } from "./DemoPipeline2LocalMissingTradeEventDiagnosticSample";
|
||||||
import type { DemoPipeline2LocalMissingTradeEventReasonSummary } from "./DemoPipeline2LocalMissingTradeEventReasonSummary";
|
import type { DemoPipeline2LocalMissingTradeEventReasonSummary } from "./DemoPipeline2LocalMissingTradeEventReasonSummary";
|
||||||
import type { DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample } from "./DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample";
|
import type { DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample } from "./DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample";
|
||||||
@@ -11,6 +12,7 @@ import type { DemoPipeline2LocalPairActionabilityDiagnosticSummary } from "./Dem
|
|||||||
import type { DemoPipeline2LocalPairDiagnosticSummary } from "./DemoPipeline2LocalPairDiagnosticSummary";
|
import type { DemoPipeline2LocalPairDiagnosticSummary } from "./DemoPipeline2LocalPairDiagnosticSummary";
|
||||||
import type { DemoPipeline2LocalPairGapDiagnosticSample } from "./DemoPipeline2LocalPairGapDiagnosticSample";
|
import type { DemoPipeline2LocalPairGapDiagnosticSample } from "./DemoPipeline2LocalPairGapDiagnosticSample";
|
||||||
import type { DemoPipeline2LocalPairTradingReadinessDiagnosticSummary } from "./DemoPipeline2LocalPairTradingReadinessDiagnosticSummary";
|
import type { DemoPipeline2LocalPairTradingReadinessDiagnosticSummary } from "./DemoPipeline2LocalPairTradingReadinessDiagnosticSummary";
|
||||||
|
import type { DemoPipeline2LocalPoolOriginDiagnosticSample } from "./DemoPipeline2LocalPoolOriginDiagnosticSample";
|
||||||
import type { DemoPipeline2LocalTokenMetadataGapDiagnosticSample } from "./DemoPipeline2LocalTokenMetadataGapDiagnosticSample";
|
import type { DemoPipeline2LocalTokenMetadataGapDiagnosticSample } from "./DemoPipeline2LocalTokenMetadataGapDiagnosticSample";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -246,6 +248,14 @@ eventClassificationSummaries: Array<DemoPipeline2LocalEventClassificationDiagnos
|
|||||||
* Missing trade events grouped by diagnostic reason.
|
* Missing trade events grouped by diagnostic reason.
|
||||||
*/
|
*/
|
||||||
missingTradeEventReasonSummaries: Array<DemoPipeline2LocalMissingTradeEventReasonSummary>,
|
missingTradeEventReasonSummaries: Array<DemoPipeline2LocalMissingTradeEventReasonSummary>,
|
||||||
|
/**
|
||||||
|
* Samples of launch-origin attributions.
|
||||||
|
*/
|
||||||
|
launchOriginSamples: Array<DemoPipeline2LocalLaunchOriginDiagnosticSample>,
|
||||||
|
/**
|
||||||
|
* Samples of pool-origin rows and their optional launch linkage.
|
||||||
|
*/
|
||||||
|
poolOriginSamples: Array<DemoPipeline2LocalPoolOriginDiagnosticSample>,
|
||||||
/**
|
/**
|
||||||
* Prioritized samples of tokens whose display metadata is still incomplete.
|
* Prioritized samples of tokens whose display metadata is still incomplete.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local pool-origin diagnostic sample for the UI.
|
||||||
|
*/
|
||||||
|
export type DemoPipeline2LocalPoolOriginDiagnosticSample = {
|
||||||
|
/**
|
||||||
|
* Pool-origin id.
|
||||||
|
*/
|
||||||
|
poolOriginId: number,
|
||||||
|
/**
|
||||||
|
* Effective DEX code attached to the pool.
|
||||||
|
*/
|
||||||
|
dexCode: string,
|
||||||
|
/**
|
||||||
|
* Pool id.
|
||||||
|
*/
|
||||||
|
poolId: number,
|
||||||
|
/**
|
||||||
|
* Pool address.
|
||||||
|
*/
|
||||||
|
poolAddress: string,
|
||||||
|
/**
|
||||||
|
* Optional pair id.
|
||||||
|
*/
|
||||||
|
pairId: number | null,
|
||||||
|
/**
|
||||||
|
* Optional pair symbol.
|
||||||
|
*/
|
||||||
|
pairSymbol: string | null,
|
||||||
|
/**
|
||||||
|
* Optional launch surface code.
|
||||||
|
*/
|
||||||
|
launchSurfaceCode: string | null,
|
||||||
|
/**
|
||||||
|
* Founding transaction signature.
|
||||||
|
*/
|
||||||
|
foundingSignature: string,
|
||||||
|
/**
|
||||||
|
* Founding effective protocol.
|
||||||
|
*/
|
||||||
|
foundingProtocolName: string,
|
||||||
|
/**
|
||||||
|
* Founding decoded event kind.
|
||||||
|
*/
|
||||||
|
foundingEventKind: string, };
|
||||||
@@ -15,6 +15,7 @@ import type { DemoPipeline2PairCandlesRequest } from "./bindings/DemoPipeline2Pa
|
|||||||
import type { DemoPipeline2PairCandlesPayload } from "./bindings/DemoPipeline2PairCandlesPayload.ts";
|
import type { DemoPipeline2PairCandlesPayload } from "./bindings/DemoPipeline2PairCandlesPayload.ts";
|
||||||
import type { DemoPipeline2LocalDiagnosticsPayload } from "./bindings/DemoPipeline2LocalDiagnosticsPayload.ts";
|
import type { DemoPipeline2LocalDiagnosticsPayload } from "./bindings/DemoPipeline2LocalDiagnosticsPayload.ts";
|
||||||
import type { DemoPipeline2LocalValidationPayload } from "./bindings/DemoPipeline2LocalValidationPayload.ts";
|
import type { DemoPipeline2LocalValidationPayload } from "./bindings/DemoPipeline2LocalValidationPayload.ts";
|
||||||
|
import type { DemoPipeline2LocalValidationRequest } from "./bindings/DemoPipeline2LocalValidationRequest.ts";
|
||||||
import type { DemoPipeline2ProgramInstructionDiscriminatorSummaryRequest } from "./bindings/DemoPipeline2ProgramInstructionDiscriminatorSummaryRequest.ts";
|
import type { DemoPipeline2ProgramInstructionDiscriminatorSummaryRequest } from "./bindings/DemoPipeline2ProgramInstructionDiscriminatorSummaryRequest.ts";
|
||||||
import type { DemoPipeline2ProgramInstructionDiscriminatorSummaryPayload } from "./bindings/DemoPipeline2ProgramInstructionDiscriminatorSummaryPayload.ts";
|
import type { DemoPipeline2ProgramInstructionDiscriminatorSummaryPayload } from "./bindings/DemoPipeline2ProgramInstructionDiscriminatorSummaryPayload.ts";
|
||||||
import { DemoPipeline2ProtocolCandidateSummaryRequest } from './bindings/DemoPipeline2ProtocolCandidateSummaryRequest.ts';
|
import { DemoPipeline2ProtocolCandidateSummaryRequest } from './bindings/DemoPipeline2ProtocolCandidateSummaryRequest.ts';
|
||||||
@@ -363,6 +364,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
const replayLocalPipelineButton = document.querySelector<HTMLButtonElement>("#demoPipeline2ReplayLocalPipelineButton");
|
const replayLocalPipelineButton = document.querySelector<HTMLButtonElement>("#demoPipeline2ReplayLocalPipelineButton");
|
||||||
const diagnoseLocalPipelineButton = document.querySelector<HTMLButtonElement>("#demoPipeline2DiagnoseLocalPipelineButton");
|
const diagnoseLocalPipelineButton = document.querySelector<HTMLButtonElement>("#demoPipeline2DiagnoseLocalPipelineButton");
|
||||||
const validateLocalPipelineButton = document.querySelector<HTMLButtonElement>("#demoPipeline2ValidateLocalPipelineButton");
|
const validateLocalPipelineButton = document.querySelector<HTMLButtonElement>("#demoPipeline2ValidateLocalPipelineButton");
|
||||||
|
const validationProfileSelect = document.querySelector<HTMLSelectElement>("#demoPipeline2ValidationProfileSelect");
|
||||||
|
|
||||||
const discriminatorProgramIdInput = document.querySelector<HTMLInputElement>("#demoPipeline2DiscriminatorProgramIdInput");
|
const discriminatorProgramIdInput = document.querySelector<HTMLInputElement>("#demoPipeline2DiscriminatorProgramIdInput");
|
||||||
const discriminatorLimitInput = document.querySelector<HTMLInputElement>("#demoPipeline2DiscriminatorLimitInput");
|
const discriminatorLimitInput = document.querySelector<HTMLInputElement>("#demoPipeline2DiscriminatorLimitInput");
|
||||||
@@ -409,6 +411,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
!replayLocalPipelineButton ||
|
!replayLocalPipelineButton ||
|
||||||
!diagnoseLocalPipelineButton ||
|
!diagnoseLocalPipelineButton ||
|
||||||
!validateLocalPipelineButton ||
|
!validateLocalPipelineButton ||
|
||||||
|
!validationProfileSelect ||
|
||||||
!discriminatorProgramIdInput ||
|
!discriminatorProgramIdInput ||
|
||||||
!discriminatorLimitInput ||
|
!discriminatorLimitInput ||
|
||||||
!loadDiscriminatorSummariesButton ||
|
!loadDiscriminatorSummariesButton ||
|
||||||
@@ -653,11 +656,19 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
validateLocalPipelineButton.addEventListener("click", async () => {
|
validateLocalPipelineButton.addEventListener("click", async () => {
|
||||||
appendLogLine(logTextarea, "[ui] validating local pipeline");
|
const request: DemoPipeline2LocalValidationRequest = {
|
||||||
|
profileCode: validationProfileSelect.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
appendLogLine(
|
||||||
|
logTextarea,
|
||||||
|
`[ui] validating local pipeline with '${request.profileCode}' profile`,
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = await invoke<DemoPipeline2LocalValidationPayload>(
|
const payload = await invoke<DemoPipeline2LocalValidationPayload>(
|
||||||
"demo_pipeline2_validate_local_pipeline",
|
"demo_pipeline2_validate_local_pipeline",
|
||||||
|
{ request },
|
||||||
);
|
);
|
||||||
|
|
||||||
localValidationTextarea.value = payload.validationJson;
|
localValidationTextarea.value = payload.validationJson;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "kb-demo-app",
|
"name": "kb-demo-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.7.38",
|
"version": "0.7.39",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -451,6 +451,10 @@ pub(crate) struct DemoPipeline2LocalPipelineDiagnosticSummary {
|
|||||||
/// Missing trade events grouped by diagnostic reason.
|
/// Missing trade events grouped by diagnostic reason.
|
||||||
pub missing_trade_event_reason_summaries:
|
pub missing_trade_event_reason_summaries:
|
||||||
std::vec::Vec<DemoPipeline2LocalMissingTradeEventReasonSummary>,
|
std::vec::Vec<DemoPipeline2LocalMissingTradeEventReasonSummary>,
|
||||||
|
/// Samples of launch-origin attributions.
|
||||||
|
pub launch_origin_samples: std::vec::Vec<DemoPipeline2LocalLaunchOriginDiagnosticSample>,
|
||||||
|
/// Samples of pool-origin rows and their optional launch linkage.
|
||||||
|
pub pool_origin_samples: std::vec::Vec<DemoPipeline2LocalPoolOriginDiagnosticSample>,
|
||||||
/// Prioritized samples of tokens whose display metadata is still incomplete.
|
/// Prioritized samples of tokens whose display metadata is still incomplete.
|
||||||
pub token_metadata_gap_samples:
|
pub token_metadata_gap_samples:
|
||||||
std::vec::Vec<DemoPipeline2LocalTokenMetadataGapDiagnosticSample>,
|
std::vec::Vec<DemoPipeline2LocalTokenMetadataGapDiagnosticSample>,
|
||||||
@@ -896,6 +900,77 @@ pub(crate) struct DemoPipeline2LocalPairGapDiagnosticSample {
|
|||||||
pub pair_candle_count: i64,
|
pub pair_candle_count: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Local launch-origin diagnostic sample for the UI.
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
|
#[ts(
|
||||||
|
export,
|
||||||
|
export_to = "../frontend/ts/bindings/DemoPipeline2LocalLaunchOriginDiagnosticSample.ts"
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct DemoPipeline2LocalLaunchOriginDiagnosticSample {
|
||||||
|
/// Launch attribution id.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub launch_attribution_id: i64,
|
||||||
|
/// Launch surface code.
|
||||||
|
pub launch_surface_code: std::string::String,
|
||||||
|
/// Launch surface display name.
|
||||||
|
pub launch_surface_name: std::string::String,
|
||||||
|
/// Transaction signature.
|
||||||
|
pub transaction_signature: std::string::String,
|
||||||
|
/// Decoded event id.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub decoded_event_id: i64,
|
||||||
|
/// Effective protocol recorded on the decoded event.
|
||||||
|
pub protocol_name: std::string::String,
|
||||||
|
/// Match kind used for attribution.
|
||||||
|
pub match_kind: std::string::String,
|
||||||
|
/// Matched key value.
|
||||||
|
pub matched_value: std::string::String,
|
||||||
|
/// Optional pool id.
|
||||||
|
#[ts(type = "number | null")]
|
||||||
|
pub pool_id: std::option::Option<i64>,
|
||||||
|
/// Optional pool address.
|
||||||
|
pub pool_address: std::option::Option<std::string::String>,
|
||||||
|
/// Optional pair id.
|
||||||
|
#[ts(type = "number | null")]
|
||||||
|
pub pair_id: std::option::Option<i64>,
|
||||||
|
/// Optional pair symbol.
|
||||||
|
pub pair_symbol: std::option::Option<std::string::String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Local pool-origin diagnostic sample for the UI.
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
|
#[ts(
|
||||||
|
export,
|
||||||
|
export_to = "../frontend/ts/bindings/DemoPipeline2LocalPoolOriginDiagnosticSample.ts"
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct DemoPipeline2LocalPoolOriginDiagnosticSample {
|
||||||
|
/// Pool-origin id.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub pool_origin_id: i64,
|
||||||
|
/// Effective DEX code attached to the pool.
|
||||||
|
pub dex_code: std::string::String,
|
||||||
|
/// Pool id.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub pool_id: i64,
|
||||||
|
/// Pool address.
|
||||||
|
pub pool_address: std::string::String,
|
||||||
|
/// Optional pair id.
|
||||||
|
#[ts(type = "number | null")]
|
||||||
|
pub pair_id: std::option::Option<i64>,
|
||||||
|
/// Optional pair symbol.
|
||||||
|
pub pair_symbol: std::option::Option<std::string::String>,
|
||||||
|
/// Optional launch surface code.
|
||||||
|
pub launch_surface_code: std::option::Option<std::string::String>,
|
||||||
|
/// Founding transaction signature.
|
||||||
|
pub founding_signature: std::string::String,
|
||||||
|
/// Founding effective protocol.
|
||||||
|
pub founding_protocol_name: std::string::String,
|
||||||
|
/// Founding decoded event kind.
|
||||||
|
pub founding_event_kind: std::string::String,
|
||||||
|
}
|
||||||
|
|
||||||
/// Local token metadata gap sample for the UI.
|
/// Local token metadata gap sample for the UI.
|
||||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
#[ts(
|
#[ts(
|
||||||
@@ -1188,7 +1263,7 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
|
|||||||
let service = kb_lib::LocalPipelineValidationService::new(database.clone());
|
let service = kb_lib::LocalPipelineValidationService::new(database.clone());
|
||||||
let profile_code = match request {
|
let profile_code = match request {
|
||||||
Some(request) => request.profile_code,
|
Some(request) => request.profile_code,
|
||||||
None => "0.7.38_token_metadata_gap_prioritization".to_string(),
|
None => "0.7.39_launch_surface_origin_baseline".to_string(),
|
||||||
};
|
};
|
||||||
let run_result = match profile_code.as_str() {
|
let run_result = match profile_code.as_str() {
|
||||||
"0.7.27" | "0.7.27_dexes_non_regression" => {
|
"0.7.27" | "0.7.27_dexes_non_regression" => {
|
||||||
@@ -1227,6 +1302,9 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
|
|||||||
"0.7.38" | "0.7.38_token_metadata_gap_prioritization" => {
|
"0.7.38" | "0.7.38_token_metadata_gap_prioritization" => {
|
||||||
service.validate_v0_7_38_current_database().await
|
service.validate_v0_7_38_current_database().await
|
||||||
},
|
},
|
||||||
|
"0.7.39" | "0.7.39_launch_surface_origin_baseline" => {
|
||||||
|
service.validate_v0_7_39_current_database().await
|
||||||
|
},
|
||||||
other => Err(kb_lib::Error::InvalidState(format!(
|
other => Err(kb_lib::Error::InvalidState(format!(
|
||||||
"unsupported local pipeline validation profile: {other}"
|
"unsupported local pipeline validation profile: {other}"
|
||||||
))),
|
))),
|
||||||
@@ -1777,6 +1855,14 @@ fn demo_pipeline2_map_local_diagnostics_summary(
|
|||||||
multi_trade_signature_pair_samples
|
multi_trade_signature_pair_samples
|
||||||
.push(demo_pipeline2_map_multi_trade_signature_pair_sample(sample));
|
.push(demo_pipeline2_map_multi_trade_signature_pair_sample(sample));
|
||||||
}
|
}
|
||||||
|
let mut launch_origin_samples = std::vec::Vec::new();
|
||||||
|
for sample in summary.launch_origin_samples {
|
||||||
|
launch_origin_samples.push(demo_pipeline2_map_launch_origin_sample(sample));
|
||||||
|
}
|
||||||
|
let mut pool_origin_samples = std::vec::Vec::new();
|
||||||
|
for sample in summary.pool_origin_samples {
|
||||||
|
pool_origin_samples.push(demo_pipeline2_map_pool_origin_sample(sample));
|
||||||
|
}
|
||||||
let mut token_metadata_gap_samples = std::vec::Vec::new();
|
let mut token_metadata_gap_samples = std::vec::Vec::new();
|
||||||
for sample in summary.token_metadata_gap_samples {
|
for sample in summary.token_metadata_gap_samples {
|
||||||
token_metadata_gap_samples.push(demo_pipeline2_map_token_metadata_gap_sample(sample));
|
token_metadata_gap_samples.push(demo_pipeline2_map_token_metadata_gap_sample(sample));
|
||||||
@@ -1853,6 +1939,8 @@ fn demo_pipeline2_map_local_diagnostics_summary(
|
|||||||
decoded_event_summaries,
|
decoded_event_summaries,
|
||||||
event_classification_summaries,
|
event_classification_summaries,
|
||||||
missing_trade_event_reason_summaries,
|
missing_trade_event_reason_summaries,
|
||||||
|
launch_origin_samples,
|
||||||
|
pool_origin_samples,
|
||||||
token_metadata_gap_samples,
|
token_metadata_gap_samples,
|
||||||
non_actionable_pair_count: summary.non_actionable_pair_count,
|
non_actionable_pair_count: summary.non_actionable_pair_count,
|
||||||
non_actionable_pair_summaries,
|
non_actionable_pair_summaries,
|
||||||
@@ -2052,6 +2140,42 @@ fn demo_pipeline2_map_multi_trade_signature_pair_sample(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn demo_pipeline2_map_launch_origin_sample(
|
||||||
|
sample: kb_lib::LocalLaunchOriginDiagnosticSampleDto,
|
||||||
|
) -> DemoPipeline2LocalLaunchOriginDiagnosticSample {
|
||||||
|
return DemoPipeline2LocalLaunchOriginDiagnosticSample {
|
||||||
|
launch_attribution_id: sample.launch_attribution_id,
|
||||||
|
launch_surface_code: sample.launch_surface_code,
|
||||||
|
launch_surface_name: sample.launch_surface_name,
|
||||||
|
transaction_signature: sample.transaction_signature,
|
||||||
|
decoded_event_id: sample.decoded_event_id,
|
||||||
|
protocol_name: sample.protocol_name,
|
||||||
|
match_kind: sample.match_kind,
|
||||||
|
matched_value: sample.matched_value,
|
||||||
|
pool_id: sample.pool_id,
|
||||||
|
pool_address: sample.pool_address,
|
||||||
|
pair_id: sample.pair_id,
|
||||||
|
pair_symbol: sample.pair_symbol,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn demo_pipeline2_map_pool_origin_sample(
|
||||||
|
sample: kb_lib::LocalPoolOriginDiagnosticSampleDto,
|
||||||
|
) -> DemoPipeline2LocalPoolOriginDiagnosticSample {
|
||||||
|
return DemoPipeline2LocalPoolOriginDiagnosticSample {
|
||||||
|
pool_origin_id: sample.pool_origin_id,
|
||||||
|
dex_code: sample.dex_code,
|
||||||
|
pool_id: sample.pool_id,
|
||||||
|
pool_address: sample.pool_address,
|
||||||
|
pair_id: sample.pair_id,
|
||||||
|
pair_symbol: sample.pair_symbol,
|
||||||
|
launch_surface_code: sample.launch_surface_code,
|
||||||
|
founding_signature: sample.founding_signature,
|
||||||
|
founding_protocol_name: sample.founding_protocol_name,
|
||||||
|
founding_event_kind: sample.founding_event_kind,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn demo_pipeline2_map_token_metadata_gap_sample(
|
fn demo_pipeline2_map_token_metadata_gap_sample(
|
||||||
sample: kb_lib::LocalTokenMetadataGapDiagnosticSampleDto,
|
sample: kb_lib::LocalTokenMetadataGapDiagnosticSampleDto,
|
||||||
) -> DemoPipeline2LocalTokenMetadataGapDiagnosticSample {
|
) -> DemoPipeline2LocalTokenMetadataGapDiagnosticSample {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "kb-demo-app",
|
"productName": "kb-demo-app",
|
||||||
"version": "0.7.38",
|
"version": "0.7.39",
|
||||||
"identifier": "com.sasedev.kb-demo-app",
|
"identifier": "com.sasedev.kb-demo-app",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ pub use dtos::LocalDecodedEventDiagnosticSummaryDto;
|
|||||||
pub use dtos::LocalDexDiagnosticSummaryDto;
|
pub use dtos::LocalDexDiagnosticSummaryDto;
|
||||||
pub use dtos::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
pub use dtos::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
||||||
pub use dtos::LocalEventClassificationDiagnosticSummaryDto;
|
pub use dtos::LocalEventClassificationDiagnosticSummaryDto;
|
||||||
|
pub use dtos::LocalLaunchOriginDiagnosticSampleDto;
|
||||||
pub use dtos::LocalMissingTradeEventDiagnosticSampleDto;
|
pub use dtos::LocalMissingTradeEventDiagnosticSampleDto;
|
||||||
pub use dtos::LocalMissingTradeEventReasonSummaryDto;
|
pub use dtos::LocalMissingTradeEventReasonSummaryDto;
|
||||||
pub use dtos::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
pub use dtos::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
||||||
@@ -44,6 +45,7 @@ pub use dtos::LocalPairGapDiagnosticSampleDto;
|
|||||||
pub use dtos::LocalPairTradingReadinessDiagnosticSummaryDto;
|
pub use dtos::LocalPairTradingReadinessDiagnosticSummaryDto;
|
||||||
pub use dtos::LocalPipelineDiagnosticCountersDto;
|
pub use dtos::LocalPipelineDiagnosticCountersDto;
|
||||||
pub use dtos::LocalPipelineDiagnosticSummaryDto;
|
pub use dtos::LocalPipelineDiagnosticSummaryDto;
|
||||||
|
pub use dtos::LocalPoolOriginDiagnosticSampleDto;
|
||||||
pub use dtos::LocalTokenMetadataGapDiagnosticSampleDto;
|
pub use dtos::LocalTokenMetadataGapDiagnosticSampleDto;
|
||||||
pub use dtos::ObservedTokenDto;
|
pub use dtos::ObservedTokenDto;
|
||||||
pub use dtos::OnchainObservationDto;
|
pub use dtos::OnchainObservationDto;
|
||||||
@@ -160,6 +162,7 @@ pub use queries::query_liquidity_events_upsert;
|
|||||||
pub use queries::query_local_decoded_event_diagnostic_list_summaries;
|
pub use queries::query_local_decoded_event_diagnostic_list_summaries;
|
||||||
pub use queries::query_local_duplicate_decoded_event_trade_diagnostic_list_samples;
|
pub use queries::query_local_duplicate_decoded_event_trade_diagnostic_list_samples;
|
||||||
pub use queries::query_local_event_classification_diagnostic_list_summaries;
|
pub use queries::query_local_event_classification_diagnostic_list_summaries;
|
||||||
|
pub use queries::query_local_launch_origin_diagnostic_list_samples;
|
||||||
pub use queries::query_local_missing_trade_event_diagnostic_list_samples;
|
pub use queries::query_local_missing_trade_event_diagnostic_list_samples;
|
||||||
pub use queries::query_local_missing_trade_event_reason_list_summaries;
|
pub use queries::query_local_missing_trade_event_reason_list_summaries;
|
||||||
pub use queries::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
pub use queries::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
||||||
@@ -171,6 +174,7 @@ pub use queries::query_local_pair_without_candle_diagnostic_list_samples;
|
|||||||
pub use queries::query_local_pair_without_trade_diagnostic_list_samples;
|
pub use queries::query_local_pair_without_trade_diagnostic_list_samples;
|
||||||
pub use queries::query_local_pipeline_diagnostic_get_counters;
|
pub use queries::query_local_pipeline_diagnostic_get_counters;
|
||||||
pub use queries::query_local_pipeline_diagnostic_list_summaries;
|
pub use queries::query_local_pipeline_diagnostic_list_summaries;
|
||||||
|
pub use queries::query_local_pool_origin_diagnostic_list_samples;
|
||||||
pub use queries::query_local_token_metadata_gap_diagnostic_list_samples;
|
pub use queries::query_local_token_metadata_gap_diagnostic_list_samples;
|
||||||
pub use queries::query_observed_tokens_get_by_mint;
|
pub use queries::query_observed_tokens_get_by_mint;
|
||||||
pub use queries::query_observed_tokens_list;
|
pub use queries::query_observed_tokens_list;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ pub(crate) use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryRow
|
|||||||
pub(crate) use local_pipeline_diagnostics::LocalDexDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalDexDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryRow;
|
||||||
|
pub(crate) use local_pipeline_diagnostics::LocalLaunchOriginDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleRow;
|
||||||
@@ -58,6 +59,7 @@ pub(crate) use local_pipeline_diagnostics::LocalPairDiagnosticSummaryRow;
|
|||||||
pub(crate) use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalPairTradingReadinessDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalPairTradingReadinessDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersRow;
|
pub(crate) use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersRow;
|
||||||
|
pub(crate) use local_pipeline_diagnostics::LocalPoolOriginDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalTokenMetadataGapDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalTokenMetadataGapDiagnosticSampleRow;
|
||||||
|
|
||||||
pub use analysis_signal::AnalysisSignalDto;
|
pub use analysis_signal::AnalysisSignalDto;
|
||||||
@@ -79,6 +81,7 @@ pub use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryDto;
|
|||||||
pub use local_pipeline_diagnostics::LocalDexDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalDexDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryDto;
|
||||||
|
pub use local_pipeline_diagnostics::LocalLaunchOriginDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryDto;
|
pub use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
||||||
@@ -89,6 +92,7 @@ pub use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleDto;
|
|||||||
pub use local_pipeline_diagnostics::LocalPairTradingReadinessDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalPairTradingReadinessDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersDto;
|
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersDto;
|
||||||
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticSummaryDto;
|
||||||
|
pub use local_pipeline_diagnostics::LocalPoolOriginDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalTokenMetadataGapDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalTokenMetadataGapDiagnosticSampleDto;
|
||||||
pub use observed_token::ObservedTokenDto;
|
pub use observed_token::ObservedTokenDto;
|
||||||
pub use onchain_observation::OnchainObservationDto;
|
pub use onchain_observation::OnchainObservationDto;
|
||||||
|
|||||||
@@ -138,6 +138,10 @@ pub struct LocalPipelineDiagnosticSummaryDto {
|
|||||||
/// Missing trade events grouped by diagnostic reason.
|
/// Missing trade events grouped by diagnostic reason.
|
||||||
pub missing_trade_event_reason_summaries:
|
pub missing_trade_event_reason_summaries:
|
||||||
std::vec::Vec<crate::LocalMissingTradeEventReasonSummaryDto>,
|
std::vec::Vec<crate::LocalMissingTradeEventReasonSummaryDto>,
|
||||||
|
/// Samples of launch-origin attributions.
|
||||||
|
pub launch_origin_samples: std::vec::Vec<crate::LocalLaunchOriginDiagnosticSampleDto>,
|
||||||
|
/// Samples of pool-origin rows and their optional launch linkage.
|
||||||
|
pub pool_origin_samples: std::vec::Vec<crate::LocalPoolOriginDiagnosticSampleDto>,
|
||||||
/// Prioritized samples of tokens whose display metadata is still incomplete.
|
/// Prioritized samples of tokens whose display metadata is still incomplete.
|
||||||
pub token_metadata_gap_samples: std::vec::Vec<crate::LocalTokenMetadataGapDiagnosticSampleDto>,
|
pub token_metadata_gap_samples: std::vec::Vec<crate::LocalTokenMetadataGapDiagnosticSampleDto>,
|
||||||
/// Total pairs with only non-actionable missing trade events.
|
/// Total pairs with only non-actionable missing trade events.
|
||||||
@@ -714,6 +718,60 @@ pub struct LocalPairGapDiagnosticSampleDto {
|
|||||||
pub pair_candle_count: i64,
|
pub pair_candle_count: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sample of a launch-origin attribution.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct LocalLaunchOriginDiagnosticSampleDto {
|
||||||
|
/// Launch attribution id.
|
||||||
|
pub launch_attribution_id: i64,
|
||||||
|
/// Launch surface code.
|
||||||
|
pub launch_surface_code: std::string::String,
|
||||||
|
/// Launch surface display name.
|
||||||
|
pub launch_surface_name: std::string::String,
|
||||||
|
/// Transaction signature.
|
||||||
|
pub transaction_signature: std::string::String,
|
||||||
|
/// Decoded event id.
|
||||||
|
pub decoded_event_id: i64,
|
||||||
|
/// Protocol that materialized the decoded event.
|
||||||
|
pub protocol_name: std::string::String,
|
||||||
|
/// Match kind used to attribute the launch surface.
|
||||||
|
pub match_kind: std::string::String,
|
||||||
|
/// Matched key value used to attribute the launch surface.
|
||||||
|
pub matched_value: std::string::String,
|
||||||
|
/// Optional related pool id.
|
||||||
|
pub pool_id: std::option::Option<i64>,
|
||||||
|
/// Optional related pool address.
|
||||||
|
pub pool_address: std::option::Option<std::string::String>,
|
||||||
|
/// Optional related pair id.
|
||||||
|
pub pair_id: std::option::Option<i64>,
|
||||||
|
/// Optional related pair symbol.
|
||||||
|
pub pair_symbol: std::option::Option<std::string::String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sample of a pool-origin row.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct LocalPoolOriginDiagnosticSampleDto {
|
||||||
|
/// Pool-origin id.
|
||||||
|
pub pool_origin_id: i64,
|
||||||
|
/// Effective DEX code attached to the pool.
|
||||||
|
pub dex_code: std::string::String,
|
||||||
|
/// Pool id.
|
||||||
|
pub pool_id: i64,
|
||||||
|
/// Pool address.
|
||||||
|
pub pool_address: std::string::String,
|
||||||
|
/// Optional pair id.
|
||||||
|
pub pair_id: std::option::Option<i64>,
|
||||||
|
/// Optional pair symbol.
|
||||||
|
pub pair_symbol: std::option::Option<std::string::String>,
|
||||||
|
/// Optional launch surface code linked through launch attribution.
|
||||||
|
pub launch_surface_code: std::option::Option<std::string::String>,
|
||||||
|
/// Founding transaction signature.
|
||||||
|
pub founding_signature: std::string::String,
|
||||||
|
/// Founding effective DEX/protocol name.
|
||||||
|
pub founding_protocol_name: std::string::String,
|
||||||
|
/// Founding decoded event kind.
|
||||||
|
pub founding_event_kind: std::string::String,
|
||||||
|
}
|
||||||
|
|
||||||
/// Prioritized sample of an incomplete token metadata row.
|
/// Prioritized sample of an incomplete token metadata row.
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct LocalTokenMetadataGapDiagnosticSampleDto {
|
pub struct LocalTokenMetadataGapDiagnosticSampleDto {
|
||||||
@@ -835,6 +893,38 @@ pub(crate) struct LocalPairGapDiagnosticSampleRow {
|
|||||||
pub(crate) pair_candle_count: i64,
|
pub(crate) pair_candle_count: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SQL row for launch-origin diagnostic samples.
|
||||||
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
|
pub(crate) struct LocalLaunchOriginDiagnosticSampleRow {
|
||||||
|
pub(crate) launch_attribution_id: i64,
|
||||||
|
pub(crate) launch_surface_code: std::string::String,
|
||||||
|
pub(crate) launch_surface_name: std::string::String,
|
||||||
|
pub(crate) transaction_signature: std::string::String,
|
||||||
|
pub(crate) decoded_event_id: i64,
|
||||||
|
pub(crate) protocol_name: std::string::String,
|
||||||
|
pub(crate) match_kind: std::string::String,
|
||||||
|
pub(crate) matched_value: std::string::String,
|
||||||
|
pub(crate) pool_id: std::option::Option<i64>,
|
||||||
|
pub(crate) pool_address: std::option::Option<std::string::String>,
|
||||||
|
pub(crate) pair_id: std::option::Option<i64>,
|
||||||
|
pub(crate) pair_symbol: std::option::Option<std::string::String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SQL row for pool-origin diagnostic samples.
|
||||||
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
|
pub(crate) struct LocalPoolOriginDiagnosticSampleRow {
|
||||||
|
pub(crate) pool_origin_id: i64,
|
||||||
|
pub(crate) dex_code: std::string::String,
|
||||||
|
pub(crate) pool_id: i64,
|
||||||
|
pub(crate) pool_address: std::string::String,
|
||||||
|
pub(crate) pair_id: std::option::Option<i64>,
|
||||||
|
pub(crate) pair_symbol: std::option::Option<std::string::String>,
|
||||||
|
pub(crate) launch_surface_code: std::option::Option<std::string::String>,
|
||||||
|
pub(crate) founding_signature: std::string::String,
|
||||||
|
pub(crate) founding_protocol_name: std::string::String,
|
||||||
|
pub(crate) founding_event_kind: std::string::String,
|
||||||
|
}
|
||||||
|
|
||||||
/// SQL row for incomplete token metadata samples.
|
/// SQL row for incomplete token metadata samples.
|
||||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
pub(crate) struct LocalTokenMetadataGapDiagnosticSampleRow {
|
pub(crate) struct LocalTokenMetadataGapDiagnosticSampleRow {
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ pub use liquidity_event::query_liquidity_events_upsert;
|
|||||||
pub use local_pipeline_diagnostics::query_local_decoded_event_diagnostic_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_decoded_event_diagnostic_list_summaries;
|
||||||
pub use local_pipeline_diagnostics::query_local_duplicate_decoded_event_trade_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_duplicate_decoded_event_trade_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_event_classification_diagnostic_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_event_classification_diagnostic_list_summaries;
|
||||||
|
pub use local_pipeline_diagnostics::query_local_launch_origin_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_missing_trade_event_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_missing_trade_event_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_missing_trade_event_reason_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_missing_trade_event_reason_list_summaries;
|
||||||
pub use local_pipeline_diagnostics::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
||||||
@@ -102,6 +103,7 @@ pub use local_pipeline_diagnostics::query_local_pair_without_candle_diagnostic_l
|
|||||||
pub use local_pipeline_diagnostics::query_local_pair_without_trade_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_pair_without_trade_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_pipeline_diagnostic_get_counters;
|
pub use local_pipeline_diagnostics::query_local_pipeline_diagnostic_get_counters;
|
||||||
pub use local_pipeline_diagnostics::query_local_pipeline_diagnostic_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_pipeline_diagnostic_list_summaries;
|
||||||
|
pub use local_pipeline_diagnostics::query_local_pool_origin_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_token_metadata_gap_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_token_metadata_gap_diagnostic_list_samples;
|
||||||
pub use observed_token::query_observed_tokens_get_by_mint;
|
pub use observed_token::query_observed_tokens_get_by_mint;
|
||||||
pub use observed_token::query_observed_tokens_list;
|
pub use observed_token::query_observed_tokens_list;
|
||||||
|
|||||||
@@ -1678,6 +1678,139 @@ LIMIT ?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lists samples of launch-origin attributions.
|
||||||
|
pub async fn query_local_launch_origin_diagnostic_list_samples(
|
||||||
|
database: &crate::Database,
|
||||||
|
limit: i64,
|
||||||
|
) -> Result<std::vec::Vec<crate::LocalLaunchOriginDiagnosticSampleDto>, crate::Error> {
|
||||||
|
match database.connection() {
|
||||||
|
crate::DatabaseConnection::Sqlite(pool) => {
|
||||||
|
let rows_result = sqlx::query_as::<
|
||||||
|
sqlx::Sqlite,
|
||||||
|
crate::db::dtos::LocalLaunchOriginDiagnosticSampleRow,
|
||||||
|
>(
|
||||||
|
r#"
|
||||||
|
SELECT
|
||||||
|
la.id AS launch_attribution_id,
|
||||||
|
ls.code AS launch_surface_code,
|
||||||
|
ls.name AS launch_surface_name,
|
||||||
|
ct.signature AS transaction_signature,
|
||||||
|
la.decoded_event_id AS decoded_event_id,
|
||||||
|
la.protocol_name AS protocol_name,
|
||||||
|
la.match_kind AS match_kind,
|
||||||
|
la.matched_value AS matched_value,
|
||||||
|
la.pool_id AS pool_id,
|
||||||
|
p.address AS pool_address,
|
||||||
|
la.pair_id AS pair_id,
|
||||||
|
pair.symbol AS pair_symbol
|
||||||
|
FROM k_sol_launch_attributions la
|
||||||
|
JOIN k_sol_launch_surfaces ls ON ls.id = la.launch_surface_id
|
||||||
|
JOIN k_sol_chain_transactions ct ON ct.id = la.transaction_id
|
||||||
|
LEFT JOIN k_sol_pools p ON p.id = la.pool_id
|
||||||
|
LEFT JOIN k_sol_pairs pair ON pair.id = la.pair_id
|
||||||
|
ORDER BY la.id DESC
|
||||||
|
LIMIT ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(limit)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await;
|
||||||
|
let rows = match rows_result {
|
||||||
|
Ok(rows) => rows,
|
||||||
|
Err(error) => {
|
||||||
|
return Err(crate::Error::Db(format!(
|
||||||
|
"cannot list launch-origin diagnostic samples on sqlite: {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut samples = std::vec::Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
samples.push(crate::LocalLaunchOriginDiagnosticSampleDto {
|
||||||
|
launch_attribution_id: row.launch_attribution_id,
|
||||||
|
launch_surface_code: row.launch_surface_code,
|
||||||
|
launch_surface_name: row.launch_surface_name,
|
||||||
|
transaction_signature: row.transaction_signature,
|
||||||
|
decoded_event_id: row.decoded_event_id,
|
||||||
|
protocol_name: row.protocol_name,
|
||||||
|
match_kind: row.match_kind,
|
||||||
|
matched_value: row.matched_value,
|
||||||
|
pool_id: row.pool_id,
|
||||||
|
pool_address: row.pool_address,
|
||||||
|
pair_id: row.pair_id,
|
||||||
|
pair_symbol: row.pair_symbol,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(samples);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lists samples of pool-origin rows and their optional launch linkage.
|
||||||
|
pub async fn query_local_pool_origin_diagnostic_list_samples(
|
||||||
|
database: &crate::Database,
|
||||||
|
limit: i64,
|
||||||
|
) -> Result<std::vec::Vec<crate::LocalPoolOriginDiagnosticSampleDto>, crate::Error> {
|
||||||
|
match database.connection() {
|
||||||
|
crate::DatabaseConnection::Sqlite(pool) => {
|
||||||
|
let rows_result = sqlx::query_as::<
|
||||||
|
sqlx::Sqlite,
|
||||||
|
crate::db::dtos::LocalPoolOriginDiagnosticSampleRow,
|
||||||
|
>(
|
||||||
|
r#"
|
||||||
|
SELECT
|
||||||
|
po.id AS pool_origin_id,
|
||||||
|
d.code AS dex_code,
|
||||||
|
po.pool_id AS pool_id,
|
||||||
|
p.address AS pool_address,
|
||||||
|
po.pair_id AS pair_id,
|
||||||
|
pair.symbol AS pair_symbol,
|
||||||
|
ls.code AS launch_surface_code,
|
||||||
|
po.founding_signature AS founding_signature,
|
||||||
|
po.founding_protocol_name AS founding_protocol_name,
|
||||||
|
po.founding_event_kind AS founding_event_kind
|
||||||
|
FROM k_sol_pool_origins po
|
||||||
|
JOIN k_sol_dexes d ON d.id = po.dex_id
|
||||||
|
JOIN k_sol_pools p ON p.id = po.pool_id
|
||||||
|
LEFT JOIN k_sol_pairs pair ON pair.id = po.pair_id
|
||||||
|
LEFT JOIN k_sol_launch_attributions la ON la.id = po.launch_attribution_id
|
||||||
|
LEFT JOIN k_sol_launch_surfaces ls ON ls.id = la.launch_surface_id
|
||||||
|
ORDER BY po.id DESC
|
||||||
|
LIMIT ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(limit)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await;
|
||||||
|
let rows = match rows_result {
|
||||||
|
Ok(rows) => rows,
|
||||||
|
Err(error) => {
|
||||||
|
return Err(crate::Error::Db(format!(
|
||||||
|
"cannot list pool-origin diagnostic samples on sqlite: {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut samples = std::vec::Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
samples.push(crate::LocalPoolOriginDiagnosticSampleDto {
|
||||||
|
pool_origin_id: row.pool_origin_id,
|
||||||
|
dex_code: row.dex_code,
|
||||||
|
pool_id: row.pool_id,
|
||||||
|
pool_address: row.pool_address,
|
||||||
|
pair_id: row.pair_id,
|
||||||
|
pair_symbol: row.pair_symbol,
|
||||||
|
launch_surface_code: row.launch_surface_code,
|
||||||
|
founding_signature: row.founding_signature,
|
||||||
|
founding_protocol_name: row.founding_protocol_name,
|
||||||
|
founding_event_kind: row.founding_event_kind,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(samples);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Lists prioritized samples of tokens whose metadata is still incomplete.
|
/// Lists prioritized samples of tokens whose metadata is still incomplete.
|
||||||
pub async fn query_local_token_metadata_gap_diagnostic_list_samples(
|
pub async fn query_local_token_metadata_gap_diagnostic_list_samples(
|
||||||
database: &crate::Database,
|
database: &crate::Database,
|
||||||
|
|||||||
@@ -573,6 +573,27 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
|
|||||||
skip_reason: Some("program_id_to_verify"),
|
skip_reason: Some("program_id_to_verify"),
|
||||||
catalog_enabled: false,
|
catalog_enabled: false,
|
||||||
},
|
},
|
||||||
|
DexSupportMatrixEntry {
|
||||||
|
code: "bonk_fun",
|
||||||
|
display_name: "Bonk.fun",
|
||||||
|
family: "bonk",
|
||||||
|
version: "unknown",
|
||||||
|
surface_type: "launch",
|
||||||
|
program_id: None,
|
||||||
|
router_program_id: None,
|
||||||
|
program_id_status: "unknown",
|
||||||
|
observed: false,
|
||||||
|
decoded: false,
|
||||||
|
materialized: false,
|
||||||
|
trade_candidate: false,
|
||||||
|
candle_candidate: false,
|
||||||
|
pair_candidate: true,
|
||||||
|
pool_candidate: true,
|
||||||
|
status: "planned",
|
||||||
|
confidence: "low",
|
||||||
|
skip_reason: Some("program_id_to_verify"),
|
||||||
|
catalog_enabled: false,
|
||||||
|
},
|
||||||
DexSupportMatrixEntry {
|
DexSupportMatrixEntry {
|
||||||
code: "okx_dex",
|
code: "okx_dex",
|
||||||
display_name: "OKX DEX",
|
display_name: "OKX DEX",
|
||||||
@@ -806,6 +827,7 @@ mod tests {
|
|||||||
"meteora_damm_v2",
|
"meteora_damm_v2",
|
||||||
"bags",
|
"bags",
|
||||||
"bonk",
|
"bonk",
|
||||||
|
"bonk_fun",
|
||||||
"okx_dex",
|
"okx_dex",
|
||||||
"boop_fun",
|
"boop_fun",
|
||||||
"moonshot",
|
"moonshot",
|
||||||
@@ -825,8 +847,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn matrix_does_not_invent_program_ids_for_unverified_planned_surfaces() {
|
fn matrix_does_not_invent_program_ids_for_unverified_planned_surfaces() {
|
||||||
let codes = [
|
let codes = [
|
||||||
|
"raydium_launchpad",
|
||||||
"bags",
|
"bags",
|
||||||
|
"letsbonk",
|
||||||
"bonk",
|
"bonk",
|
||||||
|
"bonk_fun",
|
||||||
"okx_dex",
|
"okx_dex",
|
||||||
"boop_fun",
|
"boop_fun",
|
||||||
"moonshot",
|
"moonshot",
|
||||||
@@ -879,7 +904,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn matrix_marks_launch_surfaces_as_launch_or_bonding_curve() {
|
fn matrix_marks_launch_surfaces_as_launch_or_bonding_curve() {
|
||||||
let codes = ["pump_fun", "raydium_launchlab", "bags", "moonshot", "moonit"];
|
let codes = [
|
||||||
|
"pump_fun",
|
||||||
|
"raydium_launchlab",
|
||||||
|
"raydium_launchpad",
|
||||||
|
"letsbonk",
|
||||||
|
"bonk_fun",
|
||||||
|
"bags",
|
||||||
|
"moonshot",
|
||||||
|
"moonit",
|
||||||
|
"boop_fun",
|
||||||
|
"believe",
|
||||||
|
"heaven",
|
||||||
|
];
|
||||||
for code in codes {
|
for code in codes {
|
||||||
let entry = match crate::dex_support_matrix_entry_by_code(code) {
|
let entry = match crate::dex_support_matrix_entry_by_code(code) {
|
||||||
Some(entry) => entry,
|
Some(entry) => entry,
|
||||||
@@ -894,6 +931,33 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn matrix_keeps_0_7_39_launch_surfaces_non_trade_materialized() {
|
||||||
|
let codes = [
|
||||||
|
"raydium_launchlab",
|
||||||
|
"raydium_launchpad",
|
||||||
|
"letsbonk",
|
||||||
|
"bonk_fun",
|
||||||
|
"bags",
|
||||||
|
"moonshot",
|
||||||
|
"moonit",
|
||||||
|
"boop_fun",
|
||||||
|
"believe",
|
||||||
|
"heaven",
|
||||||
|
];
|
||||||
|
for code in codes {
|
||||||
|
let entry = match crate::dex_support_matrix_entry_by_code(code) {
|
||||||
|
Some(entry) => entry,
|
||||||
|
None => panic!("missing matrix entry for {}", code),
|
||||||
|
};
|
||||||
|
assert!(!entry.decoded, "{} must not be decoded without corpus", code);
|
||||||
|
assert!(!entry.materialized, "{} must not materialize launch rows as trades", code);
|
||||||
|
assert!(!entry.trade_candidate, "{} must not create trade candidates", code);
|
||||||
|
assert!(!entry.candle_candidate, "{} must not create candle candidates", code);
|
||||||
|
assert!(!entry.catalog_enabled, "{} must not be inserted as enabled DEX", code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn matrix_dto_preserves_core_fields() {
|
fn matrix_dto_preserves_core_fields() {
|
||||||
let entry = match crate::dex_support_matrix_entry_by_code("pump_swap") {
|
let entry = match crate::dex_support_matrix_entry_by_code("pump_swap") {
|
||||||
|
|||||||
@@ -2,6 +2,77 @@
|
|||||||
|
|
||||||
//! Launch surface attribution service.
|
//! Launch surface attribution service.
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
struct BuiltinLaunchSurfaceSpec {
|
||||||
|
code: &'static str,
|
||||||
|
name: &'static str,
|
||||||
|
protocol_family: &'static str,
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const BUILTIN_LAUNCH_SURFACE_SPECS: &[BuiltinLaunchSurfaceSpec] = &[
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "raydium_launchlab",
|
||||||
|
name: "Raydium LaunchLab",
|
||||||
|
protocol_family: "raydium",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "raydium_launchpad",
|
||||||
|
name: "Raydium Launchpad",
|
||||||
|
protocol_family: "raydium",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "letsbonk",
|
||||||
|
name: "LetsBonk / Bonk.fun",
|
||||||
|
protocol_family: "bonk",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "bonk_fun",
|
||||||
|
name: "Bonk.fun",
|
||||||
|
protocol_family: "bonk",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "bags",
|
||||||
|
name: "Bags",
|
||||||
|
protocol_family: "bags",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "moonshot",
|
||||||
|
name: "Moonshot",
|
||||||
|
protocol_family: "moonshot",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "moonit",
|
||||||
|
name: "Moonit",
|
||||||
|
protocol_family: "moonit",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "boop_fun",
|
||||||
|
name: "Boop.fun",
|
||||||
|
protocol_family: "boop",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "believe",
|
||||||
|
name: "Believe",
|
||||||
|
protocol_family: "believe",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
BuiltinLaunchSurfaceSpec {
|
||||||
|
code: "heaven",
|
||||||
|
name: "Heaven",
|
||||||
|
protocol_family: "heaven",
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
/// Result of one launch surface attribution.
|
/// Result of one launch surface attribution.
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct LaunchAttributionResult {
|
pub struct LaunchAttributionResult {
|
||||||
@@ -33,57 +104,121 @@ impl LaunchOriginService {
|
|||||||
return Self { database, persistence };
|
return Self { database, persistence };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that the built-in `moonit` launch surface exists and returns its id.
|
/// Ensures that every built-in launch surface tracked by `0.7.39` exists.
|
||||||
pub async fn ensure_moonit_surface(&self) -> Result<i64, crate::Error> {
|
pub async fn ensure_target_launch_surfaces(&self) -> Result<std::vec::Vec<i64>, crate::Error> {
|
||||||
let existing_result =
|
let mut surface_ids = std::vec::Vec::new();
|
||||||
crate::query_launch_surfaces_get_by_code(self.database.as_ref(), "moonit").await;
|
for spec in BUILTIN_LAUNCH_SURFACE_SPECS {
|
||||||
let existing_option = match existing_result {
|
let surface_id_result = self.ensure_builtin_launch_surface(spec.code).await;
|
||||||
Ok(existing_option) => existing_option,
|
let surface_id = match surface_id_result {
|
||||||
|
Ok(surface_id) => surface_id,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
surface_ids.push(surface_id);
|
||||||
|
}
|
||||||
|
return Ok(surface_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures that one built-in launch surface exists and returns its id.
|
||||||
|
pub async fn ensure_builtin_launch_surface(&self, code: &str) -> Result<i64, crate::Error> {
|
||||||
|
let spec = match find_builtin_launch_surface_spec(code) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
return Err(crate::Error::InvalidState(format!(
|
||||||
|
"unknown built-in launch surface '{}'",
|
||||||
|
code
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let surface_id_result = self.ensure_launch_surface_from_spec(spec).await;
|
||||||
|
let surface_id = match surface_id_result {
|
||||||
|
Ok(surface_id) => surface_id,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
let surface_id = match existing_option {
|
if spec.code == "moonit" {
|
||||||
Some(existing) => match existing.id {
|
let suffix_key_result = crate::query_launch_surface_keys_upsert(
|
||||||
Some(surface_id) => surface_id,
|
self.database.as_ref(),
|
||||||
None => {
|
&crate::LaunchSurfaceKeyDto::new(
|
||||||
return Err(crate::Error::InvalidState(
|
surface_id,
|
||||||
"moonit launch surface has no internal id".to_string(),
|
"token_mint_suffix".to_string(),
|
||||||
));
|
"moon".to_string(),
|
||||||
},
|
),
|
||||||
},
|
)
|
||||||
None => {
|
.await;
|
||||||
let dto = crate::LaunchSurfaceDto::new(
|
if let Err(error) = suffix_key_result {
|
||||||
"moonit".to_string(),
|
return Err(error);
|
||||||
"Moonit".to_string(),
|
}
|
||||||
Some("launchpad".to_string()),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
let insert_result =
|
|
||||||
crate::query_launch_surfaces_upsert(self.database.as_ref(), &dto).await;
|
|
||||||
match insert_result {
|
|
||||||
Ok(surface_id) => surface_id,
|
|
||||||
Err(error) => return Err(error),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let suffix_key_result = crate::query_launch_surface_keys_upsert(
|
|
||||||
self.database.as_ref(),
|
|
||||||
&crate::LaunchSurfaceKeyDto::new(
|
|
||||||
surface_id,
|
|
||||||
"token_mint_suffix".to_string(),
|
|
||||||
"moon".to_string(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
if let Err(error) = suffix_key_result {
|
|
||||||
return Err(error);
|
|
||||||
}
|
}
|
||||||
return Ok(surface_id);
|
return Ok(surface_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensures that the built-in `moonit` launch surface exists and returns its id.
|
||||||
|
pub async fn ensure_moonit_surface(&self) -> Result<i64, crate::Error> {
|
||||||
|
return self.ensure_builtin_launch_surface("moonit").await;
|
||||||
|
}
|
||||||
|
|
||||||
/// Ensures that the built-in `bags` launch surface exists and returns its id.
|
/// Ensures that the built-in `bags` launch surface exists and returns its id.
|
||||||
pub async fn ensure_bags_surface(&self) -> Result<i64, crate::Error> {
|
pub async fn ensure_bags_surface(&self) -> Result<i64, crate::Error> {
|
||||||
|
return self.ensure_builtin_launch_surface("bags").await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers one generic launch-surface mapping from verified corpus/API evidence.
|
||||||
|
pub async fn register_launch_surface_mapping(
|
||||||
|
&self,
|
||||||
|
surface_code: &str,
|
||||||
|
token_mint: std::option::Option<&str>,
|
||||||
|
config_account: std::option::Option<&str>,
|
||||||
|
pool_account: std::option::Option<&str>,
|
||||||
|
creator: std::option::Option<&str>,
|
||||||
|
) -> Result<i64, crate::Error> {
|
||||||
|
let surface_id_result = self.ensure_builtin_launch_surface(surface_code).await;
|
||||||
|
let surface_id = match surface_id_result {
|
||||||
|
Ok(surface_id) => surface_id,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let key_specs = [
|
||||||
|
("token_mint", token_mint),
|
||||||
|
("config_account", config_account),
|
||||||
|
("pool_account", pool_account),
|
||||||
|
("creator", creator),
|
||||||
|
];
|
||||||
|
let mut inserted_key_count = 0_u32;
|
||||||
|
for (match_kind, match_value) in key_specs {
|
||||||
|
let match_value = match match_value {
|
||||||
|
Some(match_value) => match_value,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
if match_value.trim().is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let key_result = crate::query_launch_surface_keys_upsert(
|
||||||
|
self.database.as_ref(),
|
||||||
|
&crate::LaunchSurfaceKeyDto::new(
|
||||||
|
surface_id,
|
||||||
|
match_kind.to_string(),
|
||||||
|
match_value.to_string(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
if let Err(error) = key_result {
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
inserted_key_count += 1;
|
||||||
|
}
|
||||||
|
if inserted_key_count == 0 {
|
||||||
|
return Err(crate::Error::InvalidState(format!(
|
||||||
|
"launch surface '{}' mapping must include at least one non-empty key",
|
||||||
|
surface_code
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
return Ok(surface_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ensure_launch_surface_from_spec(
|
||||||
|
&self,
|
||||||
|
spec: BuiltinLaunchSurfaceSpec,
|
||||||
|
) -> Result<i64, crate::Error> {
|
||||||
let existing_result =
|
let existing_result =
|
||||||
crate::query_launch_surfaces_get_by_code(self.database.as_ref(), "bags").await;
|
crate::query_launch_surfaces_get_by_code(self.database.as_ref(), spec.code).await;
|
||||||
let existing_option = match existing_result {
|
let existing_option = match existing_result {
|
||||||
Ok(existing_option) => existing_option,
|
Ok(existing_option) => existing_option,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
@@ -92,17 +227,18 @@ impl LaunchOriginService {
|
|||||||
Some(existing) => match existing.id {
|
Some(existing) => match existing.id {
|
||||||
Some(surface_id) => return Ok(surface_id),
|
Some(surface_id) => return Ok(surface_id),
|
||||||
None => {
|
None => {
|
||||||
return Err(crate::Error::InvalidState(
|
return Err(crate::Error::InvalidState(format!(
|
||||||
"bags launch surface has no internal id".to_string(),
|
"{} launch surface has no internal id",
|
||||||
));
|
spec.code
|
||||||
|
)));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let dto = crate::LaunchSurfaceDto::new(
|
let dto = crate::LaunchSurfaceDto::new(
|
||||||
"bags".to_string(),
|
spec.code.to_string(),
|
||||||
"Bags".to_string(),
|
spec.name.to_string(),
|
||||||
Some("launchpad".to_string()),
|
Some(spec.protocol_family.to_string()),
|
||||||
true,
|
spec.enabled,
|
||||||
);
|
);
|
||||||
return crate::query_launch_surfaces_upsert(self.database.as_ref(), &dto).await;
|
return crate::query_launch_surfaces_upsert(self.database.as_ref(), &dto).await;
|
||||||
},
|
},
|
||||||
@@ -117,51 +253,19 @@ impl LaunchOriginService {
|
|||||||
dbc_pool_key: std::option::Option<std::string::String>,
|
dbc_pool_key: std::option::Option<std::string::String>,
|
||||||
damm_v2_pool_key: std::option::Option<std::string::String>,
|
damm_v2_pool_key: std::option::Option<std::string::String>,
|
||||||
) -> Result<i64, crate::Error> {
|
) -> Result<i64, crate::Error> {
|
||||||
let surface_id_result = self.ensure_bags_surface().await;
|
let surface_id_result = self
|
||||||
|
.register_launch_surface_mapping(
|
||||||
|
"bags",
|
||||||
|
Some(token_mint),
|
||||||
|
dbc_config_key.as_deref(),
|
||||||
|
dbc_pool_key.as_deref(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
let surface_id = match surface_id_result {
|
let surface_id = match surface_id_result {
|
||||||
Ok(surface_id) => surface_id,
|
Ok(surface_id) => surface_id,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
let token_key_result = crate::query_launch_surface_keys_upsert(
|
|
||||||
self.database.as_ref(),
|
|
||||||
&crate::LaunchSurfaceKeyDto::new(
|
|
||||||
surface_id,
|
|
||||||
"token_mint".to_string(),
|
|
||||||
token_mint.to_string(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
if let Err(error) = token_key_result {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
if let Some(dbc_config_key) = dbc_config_key {
|
|
||||||
let key_result = crate::query_launch_surface_keys_upsert(
|
|
||||||
self.database.as_ref(),
|
|
||||||
&crate::LaunchSurfaceKeyDto::new(
|
|
||||||
surface_id,
|
|
||||||
"config_account".to_string(),
|
|
||||||
dbc_config_key,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
if let Err(error) = key_result {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(dbc_pool_key) = dbc_pool_key {
|
|
||||||
let key_result = crate::query_launch_surface_keys_upsert(
|
|
||||||
self.database.as_ref(),
|
|
||||||
&crate::LaunchSurfaceKeyDto::new(
|
|
||||||
surface_id,
|
|
||||||
"pool_account".to_string(),
|
|
||||||
dbc_pool_key,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
if let Err(error) = key_result {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(damm_v2_pool_key) = damm_v2_pool_key {
|
if let Some(damm_v2_pool_key) = damm_v2_pool_key {
|
||||||
let key_result = crate::query_launch_surface_keys_upsert(
|
let key_result = crate::query_launch_surface_keys_upsert(
|
||||||
self.database.as_ref(),
|
self.database.as_ref(),
|
||||||
@@ -209,8 +313,8 @@ impl LaunchOriginService {
|
|||||||
)));
|
)));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let ensure_moonit_result = self.ensure_moonit_surface().await;
|
let ensure_surfaces_result = self.ensure_target_launch_surfaces().await;
|
||||||
if let Err(error) = ensure_moonit_result {
|
if let Err(error) = ensure_surfaces_result {
|
||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
}
|
||||||
let decoded_events_result = crate::query_dex_decoded_events_list_by_transaction_id(
|
let decoded_events_result = crate::query_dex_decoded_events_list_by_transaction_id(
|
||||||
@@ -512,6 +616,15 @@ impl LaunchOriginService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_builtin_launch_surface_spec(code: &str) -> std::option::Option<BuiltinLaunchSurfaceSpec> {
|
||||||
|
for spec in BUILTIN_LAUNCH_SURFACE_SPECS {
|
||||||
|
if spec.code == code {
|
||||||
|
return Some(*spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct MatchedLaunchSurface {
|
struct MatchedLaunchSurface {
|
||||||
launch_surface_id: i64,
|
launch_surface_id: i64,
|
||||||
@@ -866,4 +979,79 @@ mod tests {
|
|||||||
assert_eq!(listed[0].match_kind, "token_mint_suffix".to_string());
|
assert_eq!(listed[0].match_kind, "token_mint_suffix".to_string());
|
||||||
assert_eq!(listed[0].matched_value, "ExampleTokenmoon".to_string());
|
assert_eq!(listed[0].matched_value, "ExampleTokenmoon".to_string());
|
||||||
}
|
}
|
||||||
|
#[tokio::test]
|
||||||
|
async fn ensure_target_launch_surfaces_seeds_0_7_39_surfaces_without_program_ids() {
|
||||||
|
let database = make_database().await;
|
||||||
|
let service = crate::LaunchOriginService::new(database.clone());
|
||||||
|
let result = service.ensure_target_launch_surfaces().await;
|
||||||
|
let surface_ids = match result {
|
||||||
|
Ok(surface_ids) => surface_ids,
|
||||||
|
Err(error) => panic!("target launch surfaces must seed: {}", error),
|
||||||
|
};
|
||||||
|
assert_eq!(surface_ids.len(), 10);
|
||||||
|
let required_codes = [
|
||||||
|
"raydium_launchlab",
|
||||||
|
"raydium_launchpad",
|
||||||
|
"letsbonk",
|
||||||
|
"bonk_fun",
|
||||||
|
"bags",
|
||||||
|
"moonshot",
|
||||||
|
"moonit",
|
||||||
|
"boop_fun",
|
||||||
|
"believe",
|
||||||
|
"heaven",
|
||||||
|
];
|
||||||
|
for code in required_codes {
|
||||||
|
let surface_result =
|
||||||
|
crate::query_launch_surfaces_get_by_code(database.as_ref(), code).await;
|
||||||
|
let surface_option = match surface_result {
|
||||||
|
Ok(surface_option) => surface_option,
|
||||||
|
Err(error) => panic!("surface fetch must succeed: {}", error),
|
||||||
|
};
|
||||||
|
assert!(surface_option.is_some(), "missing launch surface {}", code);
|
||||||
|
}
|
||||||
|
let heaven_surface =
|
||||||
|
match crate::query_launch_surfaces_get_by_code(database.as_ref(), "heaven").await {
|
||||||
|
Ok(Some(surface)) => surface,
|
||||||
|
Ok(None) => panic!("heaven surface must exist"),
|
||||||
|
Err(error) => panic!("heaven surface fetch must succeed: {}", error),
|
||||||
|
};
|
||||||
|
assert!(!heaven_surface.is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn attribute_transaction_by_signature_detects_generic_launch_surface_mapping() {
|
||||||
|
let database = make_database().await;
|
||||||
|
let service = crate::LaunchOriginService::new(database.clone());
|
||||||
|
let register_result = service
|
||||||
|
.register_launch_surface_mapping(
|
||||||
|
"raydium_launchlab",
|
||||||
|
Some("DbcDetectTokenA111"),
|
||||||
|
Some("DbcDetectConfig111"),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
if let Err(error) = register_result {
|
||||||
|
panic!("launchlab mapping registration must succeed: {}", error);
|
||||||
|
}
|
||||||
|
seed_decoded_meteora_dbc_event(database.clone(), "sig-launch-origin-launchlab-1").await;
|
||||||
|
let result = service
|
||||||
|
.attribute_transaction_by_signature("sig-launch-origin-launchlab-1")
|
||||||
|
.await;
|
||||||
|
let results = match result {
|
||||||
|
Ok(results) => results,
|
||||||
|
Err(error) => panic!("launchlab attribution must succeed: {}", error),
|
||||||
|
};
|
||||||
|
assert_eq!(results.len(), 1);
|
||||||
|
assert!(results[0].created_attribution);
|
||||||
|
let surface_result =
|
||||||
|
crate::query_launch_surfaces_get_by_code(database.as_ref(), "raydium_launchlab").await;
|
||||||
|
let surface = match surface_result {
|
||||||
|
Ok(Some(surface)) => surface,
|
||||||
|
Ok(None) => panic!("raydium_launchlab surface must exist"),
|
||||||
|
Err(error) => panic!("surface fetch must succeed: {}", error),
|
||||||
|
};
|
||||||
|
assert_eq!(surface.id, Some(results[0].launch_surface_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ pub use constants::ARBITRAGE_BOT_6MWVT_PROGRAM_ID;
|
|||||||
/// Associated Token Account program identifier. ("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").
|
/// Associated Token Account program identifier. ("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").
|
||||||
/// @see solana_sdk::pubkey::Pubkey = spl_associated_token_account_interface::program::ID
|
/// @see solana_sdk::pubkey::Pubkey = spl_associated_token_account_interface::program::ID
|
||||||
pub use constants::ASSOCIATED_TOKEN_PROGRAM_ID;
|
pub use constants::ASSOCIATED_TOKEN_PROGRAM_ID;
|
||||||
|
/// Canonical Bonk token mint identifier.
|
||||||
|
pub use constants::BONK_MINT_ID;
|
||||||
/// BPF Loader program identifier. ("BPFLoader1111111111111111111111111111111111").
|
/// BPF Loader program identifier. ("BPFLoader1111111111111111111111111111111111").
|
||||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::bpf_loader_deprecated::ID
|
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::bpf_loader_deprecated::ID
|
||||||
pub use constants::BPF_LOADER_DEPRECATED_PROGRAM_ID;
|
pub use constants::BPF_LOADER_DEPRECATED_PROGRAM_ID;
|
||||||
@@ -171,6 +173,8 @@ pub use constants::FLUXBEAM_PROGRAM_ID;
|
|||||||
/// Incinerator program identifier. ("1nc1nerator11111111111111111111111111111111").
|
/// Incinerator program identifier. ("1nc1nerator11111111111111111111111111111111").
|
||||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::incinerator::ID
|
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::incinerator::ID
|
||||||
pub use constants::INCINERATOR_PROGRAM_ID;
|
pub use constants::INCINERATOR_PROGRAM_ID;
|
||||||
|
/// Canonical Jupiter governance token mint identifier.
|
||||||
|
pub use constants::JUP_MINT_ID;
|
||||||
/// Loader V4 program identifier. ("LoaderV411111111111111111111111111111111111").
|
/// Loader V4 program identifier. ("LoaderV411111111111111111111111111111111111").
|
||||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::loader_v4::ID
|
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::loader_v4::ID
|
||||||
pub use constants::LOADER_V4_PROGRAM_ID;
|
pub use constants::LOADER_V4_PROGRAM_ID;
|
||||||
@@ -191,6 +195,8 @@ pub use constants::ORCA_WHIRLPOOLS_PROGRAM_ID;
|
|||||||
pub use constants::PUMP_FUN_PROGRAM_ID;
|
pub use constants::PUMP_FUN_PROGRAM_ID;
|
||||||
/// PumpSwap / PumpAMM program id. ("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA").
|
/// PumpSwap / PumpAMM program id. ("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA").
|
||||||
pub use constants::PUMP_SWAP_PROGRAM_ID;
|
pub use constants::PUMP_SWAP_PROGRAM_ID;
|
||||||
|
/// Canonical Raydium token mint identifier.
|
||||||
|
pub use constants::RAY_MINT_ID;
|
||||||
/// Raydium AMM routing program id. ("routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS").
|
/// Raydium AMM routing program id. ("routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS").
|
||||||
pub use constants::RAYDIUM_AMM_ROUTING_PROGRAM_ID;
|
pub use constants::RAYDIUM_AMM_ROUTING_PROGRAM_ID;
|
||||||
/// Raydium AmmV4 program id. ("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8").
|
/// Raydium AmmV4 program id. ("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8").
|
||||||
@@ -263,19 +269,13 @@ pub use constants::SYSVAR_SLOT_HISTORY_PROGRAM_ID;
|
|||||||
/// Sysvar Stake History program identifier. ("SysvarStakeHistory1111111111111111111111111").
|
/// Sysvar Stake History program identifier. ("SysvarStakeHistory1111111111111111111111111").
|
||||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::sysvar::stake_history::ID
|
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::sysvar::stake_history::ID
|
||||||
pub use constants::SYSVAR_STAKE_HISTORY_PROGRAM_ID;
|
pub use constants::SYSVAR_STAKE_HISTORY_PROGRAM_ID;
|
||||||
/// Vote program identifier. ("Vote111111111111111111111111111111111111111").
|
|
||||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::vote::ID
|
|
||||||
pub use constants::VOTE_PROGRAM_ID;
|
|
||||||
/// Canonical Bonk token mint identifier.
|
|
||||||
pub use constants::BONK_MINT_ID;
|
|
||||||
/// Canonical Jupiter governance token mint identifier.
|
|
||||||
pub use constants::JUP_MINT_ID;
|
|
||||||
/// Canonical Raydium token mint identifier.
|
|
||||||
pub use constants::RAY_MINT_ID;
|
|
||||||
/// Canonical Solana USDC mint identifier.
|
/// Canonical Solana USDC mint identifier.
|
||||||
pub use constants::USDC_MINT_ID;
|
pub use constants::USDC_MINT_ID;
|
||||||
/// Canonical Solana USDT mint identifier.
|
/// Canonical Solana USDT mint identifier.
|
||||||
pub use constants::USDT_MINT_ID;
|
pub use constants::USDT_MINT_ID;
|
||||||
|
/// Vote program identifier. ("Vote111111111111111111111111111111111111111").
|
||||||
|
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::vote::ID
|
||||||
|
pub use constants::VOTE_PROGRAM_ID;
|
||||||
/// Wrapped SOL mint identifier. ("So11111111111111111111111111111111111111112").
|
/// Wrapped SOL mint identifier. ("So11111111111111111111111111111111111111112").
|
||||||
/// @see solana_sdk::pubkey::Pubkey = spl_token_interface::native_mint::ID
|
/// @see solana_sdk::pubkey::Pubkey = spl_token_interface::native_mint::ID
|
||||||
pub use constants::WSOL_MINT_ID;
|
pub use constants::WSOL_MINT_ID;
|
||||||
@@ -365,6 +365,8 @@ pub use db::LocalDexDiagnosticSummaryDto;
|
|||||||
pub use db::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
pub use db::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
||||||
/// Local decoded-event classification diagnostics summary.
|
/// Local decoded-event classification diagnostics summary.
|
||||||
pub use db::LocalEventClassificationDiagnosticSummaryDto;
|
pub use db::LocalEventClassificationDiagnosticSummaryDto;
|
||||||
|
/// Sample of a launch-origin attribution.
|
||||||
|
pub use db::LocalLaunchOriginDiagnosticSampleDto;
|
||||||
/// Sample of a decoded trade candidate without linked trade event.
|
/// Sample of a decoded trade candidate without linked trade event.
|
||||||
pub use db::LocalMissingTradeEventDiagnosticSampleDto;
|
pub use db::LocalMissingTradeEventDiagnosticSampleDto;
|
||||||
/// Missing trade event diagnostics grouped by reason.
|
/// Missing trade event diagnostics grouped by reason.
|
||||||
@@ -385,6 +387,8 @@ pub use db::LocalPairTradingReadinessDiagnosticSummaryDto;
|
|||||||
pub use db::LocalPipelineDiagnosticCountersDto;
|
pub use db::LocalPipelineDiagnosticCountersDto;
|
||||||
/// Local pipeline diagnostics summary.
|
/// Local pipeline diagnostics summary.
|
||||||
pub use db::LocalPipelineDiagnosticSummaryDto;
|
pub use db::LocalPipelineDiagnosticSummaryDto;
|
||||||
|
/// Sample of a pool-origin row and optional launch linkage.
|
||||||
|
pub use db::LocalPoolOriginDiagnosticSampleDto;
|
||||||
/// Prioritized sample of an incomplete token metadata row.
|
/// Prioritized sample of an incomplete token metadata row.
|
||||||
pub use db::LocalTokenMetadataGapDiagnosticSampleDto;
|
pub use db::LocalTokenMetadataGapDiagnosticSampleDto;
|
||||||
/// Source family for one on-chain observation.
|
/// Source family for one on-chain observation.
|
||||||
@@ -603,6 +607,8 @@ pub use db::query_local_decoded_event_diagnostic_list_summaries;
|
|||||||
pub use db::query_local_duplicate_decoded_event_trade_diagnostic_list_samples;
|
pub use db::query_local_duplicate_decoded_event_trade_diagnostic_list_samples;
|
||||||
/// Lists local decoded-event classification diagnostic summaries.
|
/// Lists local decoded-event classification diagnostic summaries.
|
||||||
pub use db::query_local_event_classification_diagnostic_list_summaries;
|
pub use db::query_local_event_classification_diagnostic_list_summaries;
|
||||||
|
/// Lists launch-origin diagnostic samples.
|
||||||
|
pub use db::query_local_launch_origin_diagnostic_list_samples;
|
||||||
/// Lists samples of decoded trade candidates without linked trade event.
|
/// Lists samples of decoded trade candidates without linked trade event.
|
||||||
pub use db::query_local_missing_trade_event_diagnostic_list_samples;
|
pub use db::query_local_missing_trade_event_diagnostic_list_samples;
|
||||||
/// Lists missing trade events grouped by diagnostic reason.
|
/// Lists missing trade events grouped by diagnostic reason.
|
||||||
@@ -625,6 +631,8 @@ pub use db::query_local_pair_without_trade_diagnostic_list_samples;
|
|||||||
pub use db::query_local_pipeline_diagnostic_get_counters;
|
pub use db::query_local_pipeline_diagnostic_get_counters;
|
||||||
/// Lists local DEX diagnostic summaries.
|
/// Lists local DEX diagnostic summaries.
|
||||||
pub use db::query_local_pipeline_diagnostic_list_summaries;
|
pub use db::query_local_pipeline_diagnostic_list_summaries;
|
||||||
|
/// Lists pool-origin diagnostic samples.
|
||||||
|
pub use db::query_local_pool_origin_diagnostic_list_samples;
|
||||||
/// Lists prioritized token metadata gap diagnostic samples.
|
/// Lists prioritized token metadata gap diagnostic samples.
|
||||||
pub use db::query_local_token_metadata_gap_diagnostic_list_samples;
|
pub use db::query_local_token_metadata_gap_diagnostic_list_samples;
|
||||||
/// Reads one observed token by mint.
|
/// Reads one observed token by mint.
|
||||||
|
|||||||
@@ -75,6 +75,25 @@ impl LocalPipelineDiagnosticsService {
|
|||||||
Ok(summaries) => summaries,
|
Ok(summaries) => summaries,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
|
let launch_origin_samples_result =
|
||||||
|
crate::query_local_launch_origin_diagnostic_list_samples(
|
||||||
|
self.database.as_ref(),
|
||||||
|
sample_limit,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let launch_origin_samples = match launch_origin_samples_result {
|
||||||
|
Ok(samples) => samples,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let pool_origin_samples_result = crate::query_local_pool_origin_diagnostic_list_samples(
|
||||||
|
self.database.as_ref(),
|
||||||
|
sample_limit,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let pool_origin_samples = match pool_origin_samples_result {
|
||||||
|
Ok(samples) => samples,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
let token_metadata_gap_samples_result =
|
let token_metadata_gap_samples_result =
|
||||||
crate::query_local_token_metadata_gap_diagnostic_list_samples(
|
crate::query_local_token_metadata_gap_diagnostic_list_samples(
|
||||||
self.database.as_ref(),
|
self.database.as_ref(),
|
||||||
@@ -216,6 +235,8 @@ impl LocalPipelineDiagnosticsService {
|
|||||||
decoded_event_summaries,
|
decoded_event_summaries,
|
||||||
event_classification_summaries,
|
event_classification_summaries,
|
||||||
missing_trade_event_reason_summaries,
|
missing_trade_event_reason_summaries,
|
||||||
|
launch_origin_samples,
|
||||||
|
pool_origin_samples,
|
||||||
token_metadata_gap_samples,
|
token_metadata_gap_samples,
|
||||||
non_actionable_pair_count: counters.non_actionable_pair_count,
|
non_actionable_pair_count: counters.non_actionable_pair_count,
|
||||||
non_actionable_pair_summaries,
|
non_actionable_pair_summaries,
|
||||||
|
|||||||
@@ -277,6 +277,19 @@ impl LocalPipelineValidationConfig {
|
|||||||
config.profile_code = "0.7.38_token_metadata_gap_prioritization".to_string();
|
config.profile_code = "0.7.38_token_metadata_gap_prioritization".to_string();
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the `0.7.39` launch surface origin baseline validation config.
|
||||||
|
///
|
||||||
|
/// This profile keeps the `0.7.38` metadata-gap semantics and requires the
|
||||||
|
/// static DEX matrix invariants that prevent planned launch surfaces from
|
||||||
|
/// being treated as priced trade/candle producers before corpus-backed
|
||||||
|
/// decoders are available.
|
||||||
|
pub fn v0_7_39_launch_surface_origin_baseline() -> Self {
|
||||||
|
let mut config = Self::v0_7_38_token_metadata_gap_prioritization();
|
||||||
|
config.profile_code = "0.7.39_launch_surface_origin_baseline".to_string();
|
||||||
|
config.require_dex_support_matrix_semantics = true;
|
||||||
|
return config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single local pipeline validation issue.
|
/// A single local pipeline validation issue.
|
||||||
@@ -505,6 +518,14 @@ impl LocalPipelineValidationService {
|
|||||||
crate::LocalPipelineValidationConfig::v0_7_38_token_metadata_gap_prioritization();
|
crate::LocalPipelineValidationConfig::v0_7_38_token_metadata_gap_prioritization();
|
||||||
return self.validate_current_database(&config).await;
|
return self.validate_current_database(&config).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Diagnoses the current database with the `0.7.39` launch-origin baseline profile.
|
||||||
|
pub async fn validate_v0_7_39_current_database(
|
||||||
|
&self,
|
||||||
|
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
|
||||||
|
let config = crate::LocalPipelineValidationConfig::v0_7_39_launch_surface_origin_baseline();
|
||||||
|
return self.validate_current_database(&config).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates a diagnostics summary without performing database access.
|
/// Validates a diagnostics summary without performing database access.
|
||||||
@@ -627,7 +648,8 @@ pub fn validate_local_pipeline_diagnostics_summary(
|
|||||||
|| config.profile_code == "0.7.35_non_trade_fee_reward_admin"
|
|| config.profile_code == "0.7.35_non_trade_fee_reward_admin"
|
||||||
|| config.profile_code == "0.7.36_meteora_family_consolidation"
|
|| config.profile_code == "0.7.36_meteora_family_consolidation"
|
||||||
|| config.profile_code == "0.7.37_token_metadata_catalog_enrichment"
|
|| config.profile_code == "0.7.37_token_metadata_catalog_enrichment"
|
||||||
|| config.profile_code == "0.7.38_token_metadata_gap_prioritization";
|
|| config.profile_code == "0.7.38_token_metadata_gap_prioritization"
|
||||||
|
|| config.profile_code == "0.7.39_launch_surface_origin_baseline";
|
||||||
if config.require_all_expected_dexes || missing_expected_dex_is_warning {
|
if config.require_all_expected_dexes || missing_expected_dex_is_warning {
|
||||||
for expected_dex_code in &expected_dex_codes {
|
for expected_dex_code in &expected_dex_codes {
|
||||||
if !observed_dex_codes.contains(expected_dex_code) {
|
if !observed_dex_codes.contains(expected_dex_code) {
|
||||||
@@ -875,6 +897,23 @@ fn validate_dex_support_matrix_semantics(
|
|||||||
blocking: true,
|
blocking: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (entry.status == "planned" || entry.status == "to_verify" || entry.status == "unknown")
|
||||||
|
&& entry.surface_type == "launch"
|
||||||
|
&& (entry.decoded
|
||||||
|
|| entry.materialized
|
||||||
|
|| entry.trade_candidate
|
||||||
|
|| entry.candle_candidate)
|
||||||
|
{
|
||||||
|
issues.push(crate::LocalPipelineValidationIssueDto {
|
||||||
|
code: "inactive_launch_surface_matrix_entry_actionable".to_string(),
|
||||||
|
message: format!(
|
||||||
|
"inactive launch surface '{}' must not be decoded, materialized, or priced as trade/candle candidate",
|
||||||
|
entry_code
|
||||||
|
),
|
||||||
|
subject: Some(entry_code.clone()),
|
||||||
|
blocking: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1061,6 +1100,8 @@ mod tests {
|
|||||||
decoded_event_summaries: vec![],
|
decoded_event_summaries: vec![],
|
||||||
event_classification_summaries: vec![],
|
event_classification_summaries: vec![],
|
||||||
missing_trade_event_reason_summaries: vec![],
|
missing_trade_event_reason_summaries: vec![],
|
||||||
|
launch_origin_samples: vec![],
|
||||||
|
pool_origin_samples: vec![],
|
||||||
token_metadata_gap_samples: vec![],
|
token_metadata_gap_samples: vec![],
|
||||||
non_actionable_pair_summaries: vec![],
|
non_actionable_pair_summaries: vec![],
|
||||||
missing_trade_event_samples: vec![],
|
missing_trade_event_samples: vec![],
|
||||||
@@ -1355,6 +1396,16 @@ mod tests {
|
|||||||
assert_eq!(summary.token_metadata_gap_samples.len(), 1);
|
assert_eq!(summary.token_metadata_gap_samples.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validation_accepts_0_7_39_launch_surface_origin_baseline() {
|
||||||
|
let summary = make_0_7_28_summary_with_meteora();
|
||||||
|
let config = crate::LocalPipelineValidationConfig::v0_7_39_launch_surface_origin_baseline();
|
||||||
|
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
|
||||||
|
assert!(report.validation_passed);
|
||||||
|
assert_eq!(report.validation_profile_code, "0.7.39_launch_surface_origin_baseline");
|
||||||
|
assert_eq!(report.blocking_issue_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validation_rejects_0_7_33_pair_trading_readiness_mismatch() {
|
fn validation_rejects_0_7_33_pair_trading_readiness_mismatch() {
|
||||||
let mut summary = make_0_7_28_summary_with_meteora();
|
let mut summary = make_0_7_28_summary_with_meteora();
|
||||||
|
|||||||
Reference in New Issue
Block a user