This commit is contained in:
2026-05-21 09:46:54 +02:00
parent 62831a0abe
commit 6176c5d4cd
17 changed files with 1272 additions and 116 deletions

View File

@@ -71,3 +71,4 @@
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 - Réorientation DEX-first : distinction explicite des rôles `dex_effective`, `aggregator_router`, `launch_surface` et `to_verify` dans la matrice DEX, suppression de lalias ambigu `raydium`, ajout de `metaDAO` et `Printr` comme surfaces à vérifier sans `program_id`, profil `0.7.39_dex_first_effective_swap_surfaces`, validation locale avec `blockingIssueCount = 0`, `actionableMissingTradeEventCount = 0` et `missingTradeEventCount = 0`. 0.7.39 - Réorientation DEX-first : distinction explicite des rôles `dex_effective`, `aggregator_router`, `launch_surface` et `to_verify` dans la matrice DEX, suppression de lalias ambigu `raydium`, ajout de `metaDAO` et `Printr` comme surfaces à vérifier sans `program_id`, profil `0.7.39_dex_first_effective_swap_surfaces`, validation locale avec `blockingIssueCount = 0`, `actionableMissingTradeEventCount = 0` et `missingTradeEventCount = 0`.
0.7.40 - Ajout de Demo3 pour la découverte on-chain de corpus DEX par `dex_code` / `program_id` via `getSignaturesForAddress` + `getTransaction`, extraction générique des mints observés, deltas SPL Token, comptes pool/state candidats, vaults candidats et comptes programme, ajout du backfill par signature dans Demo Pipeline 2, validation pratique sur Raydium AMM v4 avec instructions internes `675kPX...` persistées, et report de Demo4 après la première consolidation Raydium AMM v4. 0.7.40 - Ajout de Demo3 pour la découverte on-chain de corpus DEX par `dex_code` / `program_id` via `getSignaturesForAddress` + `getTransaction`, extraction générique des mints observés, deltas SPL Token, comptes pool/state candidats, vaults candidats et comptes programme, ajout du backfill par signature dans Demo Pipeline 2, validation pratique sur Raydium AMM v4 avec instructions internes `675kPX...` persistées, et report de Demo4 après la première consolidation Raydium AMM v4.
0.7.41 - Raydium AMM v4 swap decoder v1 : ajout du décodeur `raydium_amm_v4.swap` sur inner instructions `675kPX...`, extraction pool/state, authority, vaults, mints, routeSource et montants exploitables, matérialisation trades/candles sur transactions OK, profil `0.7.41_raydium_amm_v4_swap_decoder`, matrice AMM v4 passée en `supported`, et validation locale avec `blockingIssueCount = 0`, `warningCount = 0`, `actionableMissingTradeEventCount = 0`, `missingTradeEventCount = 0` et 58 trades AMM v4 matérialisés.

View File

@@ -8,7 +8,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.7.40" version = "0.7.41"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot" repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"

View File

@@ -4,7 +4,7 @@
`khadhroony-bobobot` est un workspace Rust destiné à la détection, au décodage, à lanalyse et, à terme, au trading semi-automatisé de tokens Solana. `khadhroony-bobobot` est un workspace Rust destiné à la détection, au décodage, à lanalyse 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.40` et la réorientation de travail `0.7.41 Raydium AMM v4` : 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 exploite les corpus on-chain obtenus via Demo3 et Demo Pipeline 2 pour consolider les DEX effectifs, en commençant par `raydium_amm_v4`, avant de revenir aux launch surfaces. Le README précédent décrivait surtout létat `0.3.1`. Ce fichier reflète létat de clôture `0.7.41` : 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, les diagnostics de metadata prioritaires, Demo3, le backfill par signature et le décodeur `raydium_amm_v4.swap` v1 existent déjà. La prochaine phase consolide la famille Raydium complète (`raydium_cpmm`, `raydium_clmm`, `raydium_amm_v4`, router/stable/launch surfaces différées) avant de poursuivre les autres DEX effectifs.
## 1. Objectif ## 1. Objectif
@@ -127,7 +127,7 @@ Depuis `0.7.33`, les diagnostics ajoutent une classification `pairTradingReadine
| `pump_swap` | AMM / swap | haute | conserver les invariants trade/candle et étendre les événements non-trade prouvés. | | `pump_swap` | AMM / swap | haute | conserver les invariants trade/candle et étendre les événements non-trade prouvés. |
| `raydium_cpmm` | AMM | haute | vérifier corpus swap/liquidité/admin et maintenir la matérialisation trade/candle. | | `raydium_cpmm` | AMM | haute | vérifier corpus swap/liquidité/admin et maintenir la matérialisation trade/candle. |
| `raydium_clmm` | CLMM | haute | vérifier corpus swap/liquidité/position et maintenir la matérialisation trade/candle. | | `raydium_clmm` | CLMM | haute | vérifier corpus swap/liquidité/position et maintenir la matérialisation trade/candle. |
| `raydium_amm_v4` | AMM legacy | haute | rechercher des paires/pools réels pour `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, valider `initialize2` et identifier les swaps. | | `raydium_amm_v4` | AMM legacy | haute | support v1 validé : décodage des inner swaps `675kPX...`, matérialisation trades/candles, pools/paires et payloads de montants exploitables ; prochaine étape : consolidation Raydium famille. |
| `raydium_stable_swap` | AMM legacy | moyenne | vérifier lusage réel de `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h` et ne lactiver quavec corpus. | | `raydium_stable_swap` | AMM legacy | moyenne | vérifier lusage réel de `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h` et ne lactiver quavec corpus. |
| `meteora_dlmm` | DLMM | haute | verrouiller swaps, positions, liquidité et lifecycle. | | `meteora_dlmm` | DLMM | haute | verrouiller swaps, positions, liquidité et lifecycle. |
| `meteora_damm_v1` | AMM legacy | haute | conserver le skip sans amounts exploitables et rechercher un corpus swap/liquidité exploitable. | | `meteora_damm_v1` | AMM legacy | haute | conserver le skip sans amounts exploitables et rechercher un corpus swap/liquidité exploitable. |
@@ -238,19 +238,18 @@ Les phases `0.7.38`, `0.7.39` et `0.7.40` sont considérées comme closes lorsqu
- `0.7.39_dex_first_effective_swap_surfaces` : matrice DEX-first, suppression de lalias `raydium`, ajout de `metaDAO` et `Printr` en `to_verify`, invariants locaux maintenus ; - `0.7.39_dex_first_effective_swap_surfaces` : matrice DEX-first, suppression de lalias `raydium`, ajout de `metaDAO` et `Printr` en `to_verify`, invariants locaux maintenus ;
- `0.7.40` : Demo3 découvre on-chain des signatures, mints, deltas et comptes candidats par DEX/program id, et Demo Pipeline 2 peut backfiller une signature précise. - `0.7.40` : Demo3 découvre on-chain des signatures, mints, deltas et comptes candidats par DEX/program id, et Demo Pipeline 2 peut backfiller une signature précise.
La prochaine étape est maintenant `0.7.41_raydium_amm_v4_swap_decoder_v1`. La prochaine étape est maintenant `0.7.42_raydium_family_consolidation`.
Objectifs immédiats : Objectifs immédiats :
- utiliser le corpus Raydium AMM v4 obtenu via Demo3 et backfill signature ; - verrouiller ensemble `raydium_cpmm`, `raydium_clmm` et `raydium_amm_v4` comme surfaces Raydium effectives déjà observées ;
- décoder les inner instructions `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, y compris lorsquelles sont appelées par Jupiter ou un autre routeur top-level ; - vérifier que `raydium_amm_v4` reste limité aux swaps avec mints/montants exploitables et que les transactions failed ne produisent aucun trade/candle ;
- extraire les comptes pool/state, authority, vaults et comptes utilisateur lorsque le layout observé est compatible ; - consolider les diagnostics Raydium : decoded events, trades, candles, pools, pairs, route sources, comptes pool/state et vaults ;
- dériver les montants à partir des deltas SPL Token ou transferts instruction-scoped ; - garder `raydium_router` comme `aggregator_router` non matérialisé en DEX direct ;
- produire `tradeCandidate=true` seulement si les mints et montants sont exploitables ; - garder `raydium_stable_swap`, `raydium_launchlab` et `raydium_launchpad` hors matérialisation tant quun corpus dédié ne les justifie pas ;
- conserver les routes ambiguës, failed transactions et swaps sans montants fiables comme non actionnables ; - préparer la suite Meteora/Orca/FluxBeam/DexLab sans réintroduire dalias ambigu `raydium`.
- ne créer aucun trade, metric ou candle sans payload exploitable.
`Demo4` est volontairement reportée à une version ultérieure. Pour la suite immédiate, Demo3 et Demo Pipeline 2 suffisent à produire le corpus nécessaire à la consolidation Raydium AMM v4. `Demo4` reste volontairement reportée à une version ultérieure. Pour la suite immédiate, Demo3 et Demo Pipeline 2 suffisent à produire le corpus nécessaire aux consolidations DEX.
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. 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.

View File

@@ -981,21 +981,23 @@ Décision : `0.7.40` est clos. `Demo3` et Demo Pipeline 2 suffisent pour constit
### 6.073. Version `0.7.41` — Raydium AMM v4 swap decoder v1 ### 6.073. Version `0.7.41` — Raydium AMM v4 swap decoder v1
Objectif : ajouter un premier décodeur fiable pour les swaps Raydium AMM v4 observés dans le corpus constitué avec Demo3 et Demo Pipeline 2. Objectif : ajouter un premier décodeur fiable pour les swaps Raydium AMM v4 observés dans le corpus constitué avec Demo3 et Demo Pipeline 2.
À faire : Réalisé :
- créer ou compléter le décodeur `raydium_amm_v4` pour les instructions de swap AMM v4 ; - ajout du décodeur `raydium_amm_v4.swap` pour les instructions de swap AMM v4 ;
- traiter explicitement les inner instructions dont `program_id = 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, notamment lorsquelles sont appelées via Jupiter ou un autre routeur top-level ; - prise en charge des inner instructions dont `program_id = 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, notamment lorsquelles sont appelées via Jupiter ou un autre routeur top-level ;
- conserver dans le payload décodé les informations de routage utiles : `routeSource`, `topLevelProgram`, `innerInstruction`, `instructionIndex`, `innerInstructionIndex` ; - conservation dans le payload décodé des informations de routage utiles : `routeSource`, programme parent, `innerInstruction`, `instructionIndex`, `innerInstructionIndex` et comptes complets ;
- extraire les comptes selon le layout observé lorsque le format est compatible : token program, pool/state candidat, authority, vault A, vault B, comptes intermédiaires, comptes utilisateur ; - extraction des comptes selon les layouts observés : token program, pool/state, authority, vault A, vault B, comptes intermédiaires et comptes utilisateur lorsque disponibles ;
- utiliser les deltas SPL Token et/ou les transferts inner instruction-scoped pour dériver les montants `base_amount_raw` et `quote_amount_raw` ; - dérivation des mints et montants via deltas SPL Token et transferts instruction-scoped, avec refus des cas sans payload exploitable ;
- marquer `eventActionability = trade_candidate` seulement si les montants et les mints sont exploitables ; - production de `eventActionability = trade_candidate` uniquement lorsque les mints et montants sont exploitables ;
- classer en `non_actionable_trade` les swaps ou routes dont les montants sont absents, ambigus, multi-hop non isolables ou issus de transactions failed ; - matérialisation des pools, paires, listings, `trade_events`, metrics et candles uniquement pour les transactions OK ;
- matérialiser `trade_events`, metrics et candles uniquement pour les transactions OK avec payload de montants exploitable ; - maintien des transactions failed comme traçables mais sans `trade_events`, metrics ni candles ;
- matérialiser ou mettre à jour pools/paires/listings uniquement lorsque les comptes permettent un rattachement fiable ; - ajout du profil `0.7.41_raydium_amm_v4_swap_decoder` dans la validation locale et dans Demo Pipeline 2 ;
- ajouter des tests de non-régression sur les signatures et patterns Raydium AMM v4 observés localement ; - mise à jour de la matrice DEX : `raydium_amm_v4` passe en `observed = true`, `status = supported`, `confidence = high`, sans `skipReason` ;
- maintenir `blockingIssueCount = 0`, `actionableMissingTradeEventCount = 0`, `missingTradeEventCount = 0` après replay/validation. - validation locale confirmée avec `validationPassed = true`, `blockingIssueCount = 0`, `warningCount = 0`, `actionableMissingTradeEventCount = 0`, `missingTradeEventCount = 0`, `decodedTradeCandidateWithoutAmountPayloadCount = 0` et `invalidTradeEventCount = 0`.
Corpus de travail initial : comptes candidats tels que `48yaEzz1JSHoghWYg3RGE31srN66ubfPgm4Wc5556YTG`, `SJmR8rJgzzCi4sPjGnrNsqY4akQb3jn5nsxZBhyEifC`, `EMFHrMra2GepQK9KtkQ9C65zxqdDCpQM2uKySPyNEFDA`, `58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2`, et les signatures associées issues de Demo3. Résultat de corpus validé : `raydium_amm_v4` produit 58 decoded events, 58 trade candidates, 58 trade events, 11 pools/paires et 147 candles sur la base de test Raydium AMM v4. Les routes Jupiter ou routeurs top-level restent annotées comme sources de route, tandis que le decoded event métier est attribué au DEX effectif `raydium_amm_v4`.
Décision : `0.7.41` est clos. La suite immédiate est `0.7.42_raydium_family_consolidation` afin de verrouiller ensemble `raydium_cpmm`, `raydium_clmm`, `raydium_amm_v4` et les surfaces Raydium non encore matérialisées.
### 6.074. Version `0.7.42` — Raydium effectif : famille Raydium consolidée ### 6.074. Version `0.7.42` — Raydium effectif : famille Raydium consolidée
Objectif : consolider la famille Raydium après le premier décodeur AMM v4. Objectif : consolider la famille Raydium après le premier décodeur AMM v4.
@@ -1270,30 +1272,30 @@ Le projet doit maintenir au minimum :
## 12. Priorité immédiate ## 12. Priorité immédiate
La priorité immédiate après `0.7.40` est `0.7.41_raydium_amm_v4_swap_decoder_v1`. `Demo3` et le backfill par signature donnent maintenant assez de corpus on-chain pour travailler sur Raydium AMM v4 sans inventer de layout ni promouvoir de faux pool. La priorité immédiate après `0.7.41` est `0.7.42_raydium_family_consolidation`. `raydium_amm_v4.swap` v1 est maintenant validé sur corpus réel, avec trades/candles matérialisés et aucun warning de validation. La suite doit verrouiller la famille Raydium complète avant de passer aux autres DEX effectifs.
Préconditions validées avant `0.7.41` : Préconditions validées avant `0.7.42` :
1. validation `0.7.36` acquise : Meteora consolidé, transactions failed traçables mais non actionnables, swaps sans amounts classés `non_actionable_trade`, aucun diagnostic bloquant masqué ; 1. validation `0.7.36` acquise : Meteora consolidé, transactions failed traçables mais non actionnables, swaps sans amounts classés `non_actionable_trade`, aucun diagnostic bloquant masqué ;
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. validation `0.7.39` acquise : matrice DEX-first, suppression de lalias `raydium`, `metaDAO` et `Printr` en `to_verify`, aucun `program_id` fictif ; 4. validation `0.7.39` acquise : matrice DEX-first, suppression de lalias `raydium`, `metaDAO` et `Printr` en `to_verify`, aucun `program_id` fictif ;
5. validation `0.7.40` acquise : `Demo3` découvre on-chain des signatures, mints, deltas et comptes candidats ; Demo Pipeline 2 peut backfiller une signature précise ; les instructions Raydium AMM v4 sont persistées en base ; 5. validation `0.7.40` acquise : `Demo3` découvre on-chain des signatures, mints, deltas et comptes candidats ; Demo Pipeline 2 peut backfiller une signature précise ; les instructions Raydium AMM v4 sont persistées en base ;
6. aucune transaction failed ne doit alimenter `trade_events`, metrics ou candles ; 6. validation `0.7.41` acquise : `raydium_amm_v4.swap` décode les inner instructions `675kPX...`, produit des trades/candles lorsque les montants sont exploitables, et conserve les transactions failed sans matérialisation marché ;
7. aucun decoded event AMM v4 ne doit être promu `trade_candidate` sans montants exploitables. 7. aucune transaction failed ne doit alimenter `trade_events`, metrics ou candles ;
8. aucun decoded event ne doit être promu `trade_candidate` sans montants exploitables.
Ordre de travail recommandé pour `0.7.41+` : Ordre de travail recommandé pour `0.7.42+` :
1. implémenter `raydium_amm_v4.swap` v1 à partir du corpus local : instructions internes `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`, comptes, `data_json`, deltas SPL Token et routes Jupiter ; 1. consolider ensemble `raydium_cpmm`, `raydium_clmm` et `raydium_amm_v4` comme surfaces Raydium effectives supportées ;
2. distinguer `routeSource` / routeur top-level et DEX effectif : une transaction Jupiter peut contenir un leg Raydium AMM v4, mais le decoded event métier doit rester attribué au DEX effectif ; 2. ajouter des diagnostics Raydium par surface : decoded events, trades, candles, route sources, pools, pairs, comptes pool/state, vaults et mints ;
3. matérialiser trades/candles uniquement pour transactions OK et montants fiables ; 3. vérifier que `raydium_router` reste un `aggregator_router` non matérialisé comme DEX direct ;
4. conserver les swaps ambigus ou multi-hop non isolables en `non_actionable_trade` ; 4. garder `raydium_stable_swap`, `raydium_launchlab` et `raydium_launchpad` en surfaces non matérialisées tant quun corpus dédié ne prouve pas leur exploitation ;
5. consolider ensuite la famille Raydium (`cpmm`, `clmm`, `amm_v4`, `stable_swap`, router et launch surfaces reportées) ; 5. reprendre Meteora, Orca, FluxBeam, DexLab, metaDAO et Printr avec la même approche corpus-first ;
6. reprendre Meteora, Orca, FluxBeam, DexLab, metaDAO et Printr avec la même approche corpus-first ; 6. décaler `Demo4` après la consolidation Raydium, car la découverte on-chain locale suffit pour la suite immédiate ;
7. décaler `Demo4` après la première consolidation Raydium AMM v4, car la découverte on-chain locale suffit pour la suite immédiate ; 7. ajouter ensuite `Demo10` pour le watcher WebSocket live DEX avec start/stop, subscribe/unsubscribe et écriture en base via le pipeline existant ;
8. ajouter ensuite `Demo10` pour le watcher WebSocket live DEX avec start/stop, subscribe/unsubscribe et écriture en base via le pipeline existant ; 8. reprendre seulement après cela les launch surfaces spécialisées ;
9. reprendre seulement après cela les launch surfaces spécialisées ; 9. passer ensuite à la couche wallet : création de wallet/keypair, inspection et transfert de fonds vers un autre account.
10. passer ensuite à la couche wallet : création de wallet/keypair, inspection et transfert de fonds vers un autre account.
Garde-fous constants : Garde-fous constants :

View File

@@ -179,8 +179,9 @@
<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.40_raydium_effective_surfaces" selected>0.7.340 — Raydium effective surfaces</option> <option value="0.7.41_raydium_amm_v4_swap_decoder" selected>0.7.41 — Raydium AMM v4 swap decoder</option>
<option value="0.7.39_dex_first_effective_swap_surfaces" selected>0.7.39DEX-first effective swap surfaces</option> <option value="0.7.40_raydium_effective_surfaces">0.7.40Raydium effective surfaces</option>
<option value="0.7.39_dex_first_effective_swap_surfaces">0.7.39 — DEX-first effective swap surfaces</option>
<option value="0.7.38_token_metadata_gap_prioritization">0.7.38 — token metadata gap prioritization</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>

View File

@@ -1,7 +1,7 @@
{ {
"name": "kb-demo-app", "name": "kb-demo-app",
"private": true, "private": true,
"version": "0.7.40", "version": "0.7.41",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1324,7 +1324,10 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
service.validate_v0_7_39_current_database().await service.validate_v0_7_39_current_database().await
}, },
"0.7.40" | "0.7.40_raydium_effective_surfaces" => { "0.7.40" | "0.7.40_raydium_effective_surfaces" => {
service.validate_v0_7_39_current_database().await service.validate_v0_7_40_current_database().await
},
"0.7.41" | "0.7.41_raydium_amm_v4_swap_decoder" => {
service.validate_v0_7_41_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}"

View File

@@ -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.40", "version": "0.7.41",
"identifier": "com.sasedev.kb-demo-app", "identifier": "com.sasedev.kb-demo-app",
"build": { "build": {
"beforeDevCommand": "npm run dev", "beforeDevCommand": "npm run dev",

View File

@@ -55,6 +55,7 @@ pub use pump_swap::PumpSwapTradeDecoded;
pub use raydium_amm_v4::RaydiumAmmV4DecodedEvent; pub use raydium_amm_v4::RaydiumAmmV4DecodedEvent;
pub use raydium_amm_v4::RaydiumAmmV4Decoder; pub use raydium_amm_v4::RaydiumAmmV4Decoder;
pub use raydium_amm_v4::RaydiumAmmV4Initialize2PoolDecoded; pub use raydium_amm_v4::RaydiumAmmV4Initialize2PoolDecoded;
pub use raydium_amm_v4::RaydiumAmmV4SwapDecoded;
pub use raydium_clmm::RaydiumClmmDecodedEvent; pub use raydium_clmm::RaydiumClmmDecodedEvent;
pub use raydium_clmm::RaydiumClmmSwapV2Decoded; pub use raydium_clmm::RaydiumClmmSwapV2Decoded;
pub use raydium_clmm::decode_raydium_clmm_instruction; pub use raydium_clmm::decode_raydium_clmm_instruction;

File diff suppressed because it is too large Load Diff

View File

@@ -562,6 +562,24 @@ impl DexDecodeService {
) )
.await; .await;
}, },
crate::RaydiumAmmV4DecodedEvent::Swap(event) => {
return self
.materialize_named_dex_event(
transaction,
event.transaction_id,
event.instruction_id,
"raydium_amm_v4",
event.program_id.clone(),
"raydium_amm_v4.swap",
Some(event.pool_account.clone()),
None,
Some(event.token_a_mint.clone()),
Some(event.token_b_mint.clone()),
None,
event.payload_json.clone(),
)
.await;
},
} }
} }

View File

@@ -88,6 +88,9 @@ impl DexDetectService {
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool => { crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool => {
self.detect_raydium_initialize2_pool(&transaction, decoded_event).await self.detect_raydium_initialize2_pool(&transaction, decoded_event).await
}, },
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Trade => {
self.detect_raydium_amm_v4_trade(&transaction, decoded_event).await
},
crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade => { crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade => {
self.detect_raydium_cpmm_trade(&transaction, decoded_event).await self.detect_raydium_cpmm_trade(&transaction, decoded_event).await
}, },
@@ -522,6 +525,60 @@ impl DexDetectService {
.await; .await;
} }
async fn detect_raydium_amm_v4_trade(
&self,
transaction: &crate::ChainTransactionDto,
decoded_event: &crate::DexDecodedEventDto,
) -> Result<crate::DexPoolDetectionResult, crate::Error> {
let dex_id_result =
crate::dex_catalog::ensure_known_dex(self.database.as_ref(), "raydium_amm_v4").await;
let dex_id = match dex_id_result {
Ok(dex_id) => dex_id,
Err(error) => return Err(error),
};
let payload_value_result = parse_payload_json(decoded_event.payload_json.as_str());
let payload_value = match payload_value_result {
Ok(payload_value) => payload_value,
Err(error) => return Err(error),
};
let base_vault_address = extract_payload_string_field(&payload_value, "baseVault");
let quote_vault_address = extract_payload_string_field(&payload_value, "quoteVault");
let input_result =
crate::dex_pool_materialization::DexPoolMaterializationInput::from_decoded_event(
decoded_event,
dex_id,
crate::PoolKind::Amm,
crate::PoolStatus::Active,
crate::dex_pool_materialization::DexPoolTokenOrder::AlreadyBaseQuote,
base_vault_address,
quote_vault_address,
transaction.source_endpoint_name.clone(),
);
let input = match input_result {
Ok(input) => input,
Err(error) => return Err(error),
};
let detection_result =
crate::dex_pool_materialization::materialize_dex_pool(self.database.as_ref(), &input)
.await;
let detection_result = match detection_result {
Ok(detection_result) => detection_result,
Err(error) => return Err(error),
};
let signal_result = self
.record_pool_detection_signals(
transaction,
"signal.dex.raydium_amm_v4",
&detection_result,
payload_value,
)
.await;
if let Err(error) = signal_result {
return Err(error);
}
return Ok(detection_result);
}
async fn detect_raydium_clmm_trade( async fn detect_raydium_clmm_trade(
&self, &self,
transaction: &crate::ChainTransactionDto, transaction: &crate::ChainTransactionDto,

View File

@@ -7,6 +7,8 @@
pub(crate) enum DexDetectionRoute { pub(crate) enum DexDetectionRoute {
/// Raydium AMM v4 initialize2 pool route. /// Raydium AMM v4 initialize2 pool route.
RaydiumAmmV4Initialize2Pool, RaydiumAmmV4Initialize2Pool,
/// Raydium AMM v4 trade route.
RaydiumAmmV4Trade,
/// Raydium CPMM trade route. /// Raydium CPMM trade route.
RaydiumCpmmTrade, RaydiumCpmmTrade,
/// Raydium CLMM trade route. /// Raydium CLMM trade route.
@@ -45,6 +47,9 @@ pub(crate) fn dex_detection_route(
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool, crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool,
); );
}, },
("raydium_amm_v4", "raydium_amm_v4.swap") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Trade);
},
("raydium_cpmm", "raydium_cpmm.swap_base_input") => { ("raydium_cpmm", "raydium_cpmm.swap_base_input") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade); return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade);
}, },

View File

@@ -235,16 +235,16 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
program_id: Some(crate::RAYDIUM_AMM_V4_PROGRAM_ID), program_id: Some(crate::RAYDIUM_AMM_V4_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
observed: false, observed: true,
decoded: true, decoded: true,
materialized: true, materialized: true,
trade_candidate: true, trade_candidate: true,
candle_candidate: true, candle_candidate: true,
pair_candidate: true, pair_candidate: true,
pool_candidate: true, pool_candidate: true,
status: "partial", status: "supported",
confidence: "medium", confidence: "high",
skip_reason: Some("not_observed_in_0_7_28_replay"), skip_reason: None,
catalog_enabled: true, catalog_enabled: true,
}, },
DexSupportMatrixEntry { DexSupportMatrixEntry {
@@ -949,6 +949,22 @@ mod tests {
assert_eq!(raydium_entry.code, "raydium_amm_v4"); assert_eq!(raydium_entry.code, "raydium_amm_v4");
} }
#[test]
fn matrix_marks_raydium_amm_v4_supported_after_0_7_41() {
let entry = match crate::dex_support_matrix_entry_by_code("raydium_amm_v4") {
Some(entry) => entry,
None => panic!("expected raydium_amm_v4 matrix entry"),
};
assert!(entry.observed);
assert!(entry.decoded);
assert!(entry.materialized);
assert!(entry.trade_candidate);
assert!(entry.candle_candidate);
assert_eq!(entry.status, "supported");
assert_eq!(entry.confidence, "high");
assert_eq!(entry.skip_reason, None);
}
#[test] #[test]
fn matrix_marks_partial_meteora_damm_v1_correctly() { fn matrix_marks_partial_meteora_damm_v1_correctly() {
let entry = match crate::dex_support_matrix_entry_by_code("meteora_damm_v1") { let entry = match crate::dex_support_matrix_entry_by_code("meteora_damm_v1") {

View File

@@ -923,6 +923,8 @@ pub use dex::RaydiumAmmV4DecodedEvent;
pub use dex::RaydiumAmmV4Decoder; pub use dex::RaydiumAmmV4Decoder;
/// Decoded Raydium AmmV4 initialize2 pool event. /// Decoded Raydium AmmV4 initialize2 pool event.
pub use dex::RaydiumAmmV4Initialize2PoolDecoded; pub use dex::RaydiumAmmV4Initialize2PoolDecoded;
/// Decoded Raydium AMM v4 swap event.
pub use dex::RaydiumAmmV4SwapDecoded;
/// Decoded Raydium CLMM event. /// Decoded Raydium CLMM event.
pub use dex::RaydiumClmmDecodedEvent; pub use dex::RaydiumClmmDecodedEvent;
/// Decoded Raydium CLMM swap_v2 instruction. /// Decoded Raydium CLMM swap_v2 instruction.

View File

@@ -310,6 +310,20 @@ impl LocalPipelineValidationConfig {
return config; return config;
} }
/// Builds the `0.7.41` Raydium AMM v4 swap decoder validation config.
///
/// This profile keeps the Raydium surface diagnostics and labels validation
/// runs produced after the AMM v4 swap decoder is active. Missing AMM v4
/// remains a warning so empty or unrelated local corpora stay inspectable.
pub fn v0_7_41_raydium_amm_v4_swap_decoder() -> Self {
let mut config = Self::v0_7_40_raydium_effective_surfaces();
config.profile_code = "0.7.41_raydium_amm_v4_swap_decoder".to_string();
config.expected_dex_codes = vec!["raydium_amm_v4".to_string()];
config.require_all_expected_dexes = false;
config.allow_unexpected_dexes = true;
return config;
}
/// Builds the legacy `0.7.39` launch-surface validation alias. /// Builds the legacy `0.7.39` launch-surface validation alias.
/// ///
/// The implementation now delegates to the DEX-first profile so callers that /// The implementation now delegates to the DEX-first profile so callers that
@@ -551,7 +565,8 @@ impl LocalPipelineValidationService {
pub async fn validate_v0_7_39_current_database( pub async fn validate_v0_7_39_current_database(
&self, &self,
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> { ) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
let config = crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces(); let config =
crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
return self.validate_current_database(&config).await; return self.validate_current_database(&config).await;
} }
@@ -562,6 +577,14 @@ impl LocalPipelineValidationService {
let config = crate::LocalPipelineValidationConfig::v0_7_40_raydium_effective_surfaces(); let config = crate::LocalPipelineValidationConfig::v0_7_40_raydium_effective_surfaces();
return self.validate_current_database(&config).await; return self.validate_current_database(&config).await;
} }
/// Diagnoses the current database with the `0.7.41` Raydium AMM v4 profile.
pub async fn validate_v0_7_41_current_database(
&self,
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
let config = crate::LocalPipelineValidationConfig::v0_7_41_raydium_amm_v4_swap_decoder();
return self.validate_current_database(&config).await;
}
} }
/// Validates a diagnostics summary without performing database access. /// Validates a diagnostics summary without performing database access.
@@ -687,7 +710,8 @@ pub fn validate_local_pipeline_diagnostics_summary(
|| 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_dex_first_effective_swap_surfaces" || config.profile_code == "0.7.39_dex_first_effective_swap_surfaces"
|| config.profile_code == "0.7.39_launch_surface_origin_baseline" || config.profile_code == "0.7.39_launch_surface_origin_baseline"
|| config.profile_code == "0.7.40_raydium_effective_surfaces"; || config.profile_code == "0.7.40_raydium_effective_surfaces"
|| config.profile_code == "0.7.41_raydium_amm_v4_swap_decoder";
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) {
@@ -1112,27 +1136,25 @@ mod tests {
pair_candle_count: 131, pair_candle_count: 131,
}, },
], ],
raydium_surface_summaries: vec![ raydium_surface_summaries: vec![crate::LocalRaydiumSurfaceDiagnosticSummaryDto {
crate::LocalRaydiumSurfaceDiagnosticSummaryDto { dex_code: "raydium_clmm".to_string(),
dex_code: "raydium_clmm".to_string(), display_name: "Raydium CLMM".to_string(),
display_name: "Raydium CLMM".to_string(), surface_role: "dex_effective".to_string(),
surface_role: "dex_effective".to_string(), program_id: Some(crate::RAYDIUM_CLMM_PROGRAM_ID.to_string()),
program_id: Some(crate::RAYDIUM_CLMM_PROGRAM_ID.to_string()), program_id_status: "known".to_string(),
program_id_status: "known".to_string(), status: "supported".to_string(),
status: "supported".to_string(), catalog_enabled: true,
catalog_enabled: true, instruction_count: 106,
instruction_count: 106, transaction_count: 101,
transaction_count: 101, decoded_event_count: 106,
decoded_event_count: 106, trade_event_count: 101,
trade_event_count: 101, pair_candle_count: 131,
pair_candle_count: 131, latest_slot: Some(1),
latest_slot: Some(1), latest_signature: Some("raydium_clmm_fixture".to_string()),
latest_signature: Some("raydium_clmm_fixture".to_string()), observed_in_current_corpus: true,
observed_in_current_corpus: true, decoded_in_current_corpus: true,
decoded_in_current_corpus: true, trade_materialized_in_current_corpus: true,
trade_materialized_in_current_corpus: true, }],
},
],
pair_summaries: vec![], pair_summaries: vec![],
pair_actionability_summaries: vec![ pair_actionability_summaries: vec![
crate::LocalPairActionabilityDiagnosticSummaryDto { crate::LocalPairActionabilityDiagnosticSummaryDto {
@@ -1490,7 +1512,8 @@ mod tests {
#[test] #[test]
fn validation_accepts_0_7_39_dex_first_effective_swap_surfaces() { fn validation_accepts_0_7_39_dex_first_effective_swap_surfaces() {
let summary = make_0_7_28_summary_with_meteora(); let summary = make_0_7_28_summary_with_meteora();
let config = crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces(); let config =
crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config); let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
assert!(report.validation_passed); assert!(report.validation_passed);
assert_eq!(report.validation_profile_code, "0.7.39_dex_first_effective_swap_surfaces"); assert_eq!(report.validation_profile_code, "0.7.39_dex_first_effective_swap_surfaces");
@@ -1509,6 +1532,18 @@ mod tests {
assert!(report.expected_dex_codes.contains(&"raydium_amm_v4".to_string())); assert!(report.expected_dex_codes.contains(&"raydium_amm_v4".to_string()));
} }
#[test]
fn validation_accepts_0_7_41_raydium_amm_v4_swap_decoder_profile() {
let summary = make_0_7_28_summary_with_meteora();
let config = crate::LocalPipelineValidationConfig::v0_7_41_raydium_amm_v4_swap_decoder();
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
assert!(report.validation_passed);
assert_eq!(report.validation_profile_code, "0.7.41_raydium_amm_v4_swap_decoder");
assert_eq!(report.blocking_issue_count, 0);
assert!(report.warning_count >= 1);
assert!(report.expected_dex_codes.contains(&"raydium_amm_v4".to_string()));
}
#[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();

View File

@@ -96,7 +96,8 @@ pub(crate) async fn resolve_trade_amounts(
return Err(error); return Err(error);
} }
} }
if (input.decoded_event.event_kind.starts_with("raydium_cpmm.") if (input.decoded_event.event_kind.starts_with("raydium_amm_v4.")
|| input.decoded_event.event_kind.starts_with("raydium_cpmm.")
|| input.decoded_event.event_kind.starts_with("raydium_clmm.")) || input.decoded_event.event_kind.starts_with("raydium_clmm."))
&& (base_amount_raw.is_none() && (base_amount_raw.is_none()
|| quote_amount_raw.is_none() || quote_amount_raw.is_none()
@@ -114,6 +115,21 @@ pub(crate) async fn resolve_trade_amounts(
return Err(error); return Err(error);
} }
} }
if input.decoded_event.event_kind.starts_with("raydium_amm_v4.")
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
{
let resolution_result = crate::trade_amount_resolution::apply_vault_balance_delta_fallback(
input,
input.base_vault_address,
input.quote_vault_address,
&mut base_amount_raw,
&mut quote_amount_raw,
&mut price_quote_per_base,
);
if let Err(error) = resolution_result {
return Err(error);
}
}
if input.decoded_event.event_kind.starts_with("raydium_cpmm.") if input.decoded_event.event_kind.starts_with("raydium_cpmm.")
&& (base_amount_raw.is_none() || quote_amount_raw.is_none()) && (base_amount_raw.is_none() || quote_amount_raw.is_none())
{ {
@@ -204,6 +220,17 @@ pub(crate) async fn resolve_trade_amounts(
return Err(error); return Err(error);
} }
} }
if input.decoded_event.event_kind.starts_with("raydium_amm_v4.") {
let vault_side = crate::trade_amount_resolution::infer_trade_side_from_vault_balance_deltas(
input.transaction.meta_json.as_deref(),
input.transaction.transaction_json.as_str(),
input.base_vault_address,
input.quote_vault_address,
);
if vault_side.is_some() {
resolved_trade_side = vault_side;
}
}
if input.decoded_event.event_kind.starts_with("meteora_dlmm.") { if input.decoded_event.event_kind.starts_with("meteora_dlmm.") {
let vault_side = crate::trade_amount_resolution::infer_trade_side_from_vault_balance_deltas( let vault_side = crate::trade_amount_resolution::infer_trade_side_from_vault_balance_deltas(
input.transaction.meta_json.as_deref(), input.transaction.meta_json.as_deref(),