This commit is contained in:
2026-06-09 10:13:03 +02:00
parent f2ea1a392f
commit bfdb2e69ae
41 changed files with 4485 additions and 1124 deletions

View File

@@ -8,7 +8,9 @@ Reprise du projet `khadhroony-bobobot` après clôture de `0.7.50 raydium_launch
Utiliser la dernière archive complète du workspace intégrant les deltas validés jusqu'à :
```text
0.7.50-raydium-launchpad-final
```
Joindre aussi les docs et SQL de validation à jour :
@@ -20,6 +22,7 @@ docs/DEX_DECODER_MATRIX.md
docs/DEX_EVENT_COVERAGE_MATRIX.md
docs/DB_EVENT_MODEL_REVIEW.md
docs/reports/RAYDIUM_LAUNCHPAD_EVENT_COVERAGE_REPORT.md
docs/reports/RAYDIUM_CPMM_EVENT_COVERAGE_REPORT.md
validation_sql/SQL_VALIDATION_RAYDIUM_LAUNCHPAD_0_7_50.sql
validation_sql/SQL_VALIDATION_RAYDIUM_CPMM_AUDIT_CLEANUP_0_7_50_FINAL.sql
validation_sql/SQL_VALIDATION_RAYDIUM_CPMM_0_7_50_RECHECK.sql
@@ -30,20 +33,21 @@ validation_sql/SQL_VALIDATION_RAYDIUM_CLMM_0_7_50_RECHECK.sql
`0.7.50` a clôturé `raydium_launchpad` et consolidé les rechecks CPMM/CLMM.
Dernier replay local rapporté avant clôture :
Dernier replay local rapporté après cleanup final CPMM :
```text
1103 replayed
1124 replayed
0 decode skipped
1124 ledger upserts
542 unsafe ledger rows
539 unsafe ledger rows
561 trades
50 liquidity
13 lifecycle
0 tokenAccount
2224 candle upserts
instructionObservations = 7013
instructionObservations = 7010
resetDeleted = 1182
catalog = 37 tokens / 40 pools / 40 pairs
```
Points de clôture à préserver :
@@ -53,13 +57,16 @@ raydium_launchpad : surface canonique, program id LanMV9sAd7wArD4vJFi2qDdfnVhFxY
Launchpad trade_event matérialisé seulement quand corpus + successful tx le prouvent
Launchpad initialize* fournit le catalogue pool/pair, pas de faux trade/candle
CPMM 40f4bc78a7e9690a est raydium_cpmm.anchor_idl_instruction decoded-only
CPMM residual raydium_cpmm.instruction_audit 40f4bc78a7e9690a doit être nettoyé après replay final
CPMM residual raydium_cpmm.instruction_audit 40f4bc78a7e9690a = vide après replay final
CPMM decoded event without coverage entry = vide après replay final
CPMM upstream_git.instruction_match fallback résiduel = vide
CPMM non-swap materialization gap hors failed tx = vide
CLMM residual instruction_audit / upstream fallback doivent rester vides
k_sol_instruction_observations reste une table technique, pas une table métier
Solscan instruction=<discriminator> est une aide de découverte, pas une preuve métier
```
Requête CPMM post-fix obligatoire :
Requêtes CPMM post-fix obligatoires avant d'ouvrir `0.7.51` :
```sql
SELECT
@@ -73,7 +80,38 @@ GROUP BY discriminator_hex
ORDER BY audit_count DESC, discriminator_hex;
```
Cette requête doit être vide après replay `forceDexDecode=yes`.
```sql
SELECT
de.event_kind,
COUNT(*) AS decoded_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_dex_event_coverage_entries ce
ON ce.decoder_code = 'raydium_cpmm'
AND ce.local_event_kind = de.event_kind
WHERE de.protocol_name = 'raydium_cpmm'
AND ce.id IS NULL
GROUP BY de.event_kind
ORDER BY decoded_count DESC, de.event_kind;
```
Ces deux requêtes doivent être vides après replay `forceDexDecode=yes`.
## Décision de reprise
Ouvrir une nouvelle tranche :
```text
0.7.51 raydium_amm_v4
```
Ne pas commencer par `raydium_pool_v4` comme nouveau decoder autonome tant que son program id et son rôle métier ne sont pas prouvés localement.
`raydium_pool_v4` doit être traité dans `0.7.51` comme une **source à auditer / comparer** avec `raydium_amm_v4`, pas comme version déjà décidée. La roadmap peut conserver une entrée de décision `raydium_pool_v4 audit / program-id decision`, mais cette entrée doit être reformulée comme décision conditionnelle :
```text
si raydium_pool_v4 correspond au même program id AMM v4 ou à un layout alternatif -> intégrer à raydium_amm_v4
si raydium_pool_v4 correspond à un autre program id / strategy / farm / pool wrapper -> créer une tranche dédiée seulement après corpus local
```
## Objectif `0.7.51` — `raydium_amm_v4`
@@ -84,6 +122,7 @@ swaps
pool lifecycle / pool_create
add_liquidity / remove_liquidity
fees / admin/config
open_orders / target_orders / serum/openbook side effects documentés
side effects SPL Token / Token-2022 documentés mais non promus comme raydium_amm_v4.* directs
fallback instruction_audit nettoyé quand une entrée locale spécialisée couvre l'instruction
coverage entries synchronisées et rafraîchies
@@ -108,18 +147,75 @@ https://solscan.io/account/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8#programI
https://solscan.io/account/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8?instruction=<DISCRIMINATOR>&hide_spam=true&hide_failed=true&show_related=false&sort=desc
```
## Nouvelle base de travail
Démarrer `0.7.51` sur une base SQLite vide dédiée.
Avant le replay de validation complet, prévoir un corpus initial construit volontairement :
```text
1. Demo3 program_id = 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
2. Solscan Program IDL + instruction=<DISCRIMINATOR>
3. backfill Demo2 de signatures contenant des instructions AMM v4 variées
4. backfill de pools AMM v4 quand Demo3/Solscan fournit un AMM/pool account fiable
```
Ne pas interpréter l'absence de résultat Solscan comme absence on-chain définitive.
## Sources Git/IDL à utiliser systématiquement
Sources globales :
```text
https://github.com/sevenlabs-hq/carbon/tree/main/decoders
https://github.com/0xfnzero/solana-streamer
https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl
https://github.com/0xfnzero/sol-parser-sdk/tree/main/idls
https://github.com/pinax-network/substreams-solana-idls/tree/main/src
https://github.com/hodlwarden/solana-tx-parser/tree/main/src
https://docs.vybenetwork.com/docs/available-dexs-amms
```
Pour AMM v4, vérifier aussi les IDL/JSON Raydium legacy présents dans fnzero, notamment les fichiers autour de `raydium_amm_v4` / `raydium_pool_v4`, sans promouvoir `raydium_pool_v4` tant que son program id et son rôle métier ne sont pas prouvés localement.
Sources spécifiques `raydium_amm_v4` à vérifier en priorité :
```text
https://github.com/sevenlabs-hq/carbon/tree/main/decoders/raydium-amm-v4-decoder
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/amm
https://github.com/0xfnzero/sol-parser-sdk/blob/main/idl/raydium_amm_v4.json
https://github.com/0xfnzero/sol-parser-sdk/blob/main/idls/raydium_amm_v4.json
https://github.com/0xfnzero/sol-parser-sdk/blob/main/idl/raydium_pool_v4.json
https://github.com/0xfnzero/sol-parser-sdk/blob/main/idls/raydium_pool_v4.json
https://solscan.io/account/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8#programIdl
```
## Vérification obligatoire `raydium_pool_v4`
Avant de coder une tranche séparée `raydium_pool_v4`, faire une vérification explicite :
```text
1. comparer idl/raydium_pool_v4.json et idls/raydium_pool_v4.json
2. comparer idl/raydium_amm_v4.json et idls/raydium_amm_v4.json
3. chercher si raydium_pool_v4 contient un program id explicite
4. comparer les instructions communes : initialize, initialize2, deposit, withdraw, swapBaseIn, swapBaseOut, monitorStep, admin/config
5. vérifier si raydium_pool_v4 décrit :
- le même Raydium AMM v4 program id 675kPX...
- un layout alternatif d'instruction
- un wrapper strategy / pool / farming / lending
- une ancienne ABI non directement liée au program id 675kPX...
6. ne pas promouvoir `raydium_pool_v4` sans corpus local :
- k_sol_instruction_observations
- decoded events locaux
- coverage local_event_kind
- absence de fallback upstream
```
Décision attendue dans `0.7.51` :
```text
Option A : raydium_pool_v4 = alias/source complémentaire de raydium_amm_v4 -> intégrer ses discriminants/layouts dans raydium_amm_v4 et supprimer la version roadmap autonome.
Option B : raydium_pool_v4 = autre program id / autre surface -> conserver une future version dédiée avec program id prouvé.
Option C : raydium_pool_v4 = IDL ambiguë / strategy wrapper sans corpus -> garder en audit roadmap, pas de decoder local.
```
## Règles fixes
@@ -150,10 +246,11 @@ instruction_audit et upstream_git.instruction_match doivent être nettoyés quan
1. Créer une nouvelle base SQLite dédiée `0.7.51`.
2. Inventorier Carbon/fnzero/Pinax/Solscan Program IDL pour `raydium_amm_v4`.
3. Synchroniser `k_sol_dex_event_coverage_entries` avec `decoder_code = raydium_amm_v4`.
4. Utiliser Solscan `instruction=<discriminator>` pour obtenir rapidement des signatures non failed.
5. Backfill Demo2 signature/pool.
6. Replay local avec :
3. Auditer `raydium_pool_v4` avant de décider si la roadmap garde une tranche dédiée.
4. Synchroniser `k_sol_dex_event_coverage_entries` avec `decoder_code = raydium_amm_v4`.
5. Utiliser Solscan `instruction=<discriminator>` pour obtenir rapidement des signatures non failed.
6. Backfill Demo2 signature/pool sur corpus varié.
7. Replay local avec :
```text
skipDexDecode = no
@@ -161,7 +258,7 @@ forceDexDecode = yes
deferInstructionObservations = yes
```
7. Vérifier :
8. Vérifier :
```text
coverage listed/observed/materialized
@@ -170,6 +267,101 @@ residual upstream_git.instruction_match
failed tx materialization = 0
non-trade trade_count = 0
trade/candle only for swap events validés
raydium_pool_v4 decision documented
```
## SQL de contrôle minimal `0.7.51`
Coverage AMM v4 :
```sql
SELECT
entry_name,
entry_kind,
event_family,
expected_db_target,
proof_status,
local_event_kind,
discriminator_hex,
observed_count,
materialized_count,
trade_count
FROM k_sol_dex_event_coverage_entries
WHERE decoder_code = 'raydium_amm_v4'
ORDER BY entry_kind, entry_name, discriminator_hex;
```
Instruction observations :
```sql
SELECT
instruction_name,
discriminator_hex,
COUNT(*) AS observed_count,
COUNT(DISTINCT signature) AS tx_count
FROM k_sol_instruction_observations
WHERE decoder_code = 'raydium_amm_v4'
GROUP BY instruction_name, discriminator_hex
ORDER BY observed_count DESC, instruction_name, discriminator_hex;
```
Residual audit :
```sql
SELECT
json_extract(payload_json, '$.discriminatorHex') AS discriminator_hex,
COUNT(*) AS audit_count,
COUNT(DISTINCT transaction_id) AS tx_count
FROM k_sol_dex_decoded_events
WHERE protocol_name = 'raydium_amm_v4'
AND event_kind = 'raydium_amm_v4.instruction_audit'
GROUP BY discriminator_hex
ORDER BY audit_count DESC, discriminator_hex;
```
Fallback upstream :
```sql
SELECT
json_extract(ug.payload_json, '$.upstreamDecoderCode') AS upstream_decoder_code,
json_extract(ug.payload_json, '$.upstreamEntryName') AS entry_name,
json_extract(ug.payload_json, '$.upstreamDiscriminatorHex') AS discriminator_hex,
json_extract(ug.payload_json, '$.upstreamSourceRepo') AS source_repo,
COUNT(*) AS fallback_count,
COUNT(DISTINCT ug.transaction_id) AS tx_count
FROM k_sol_dex_decoded_events ug
JOIN k_sol_dex_event_coverage_entries ce
ON ce.decoder_code = json_extract(ug.payload_json, '$.upstreamDecoderCode')
AND ce.entry_name = json_extract(ug.payload_json, '$.upstreamEntryName')
AND ce.discriminator_hex = json_extract(ug.payload_json, '$.upstreamDiscriminatorHex')
AND ce.local_event_kind IS NOT NULL
AND ce.local_event_kind <> ''
WHERE ug.protocol_name = 'upstream_git'
AND ug.event_kind = 'upstream_git.instruction_match'
AND json_extract(ug.payload_json, '$.upstreamDecoderCode') = 'raydium_amm_v4'
GROUP BY upstream_decoder_code, entry_name, discriminator_hex, source_repo
ORDER BY fallback_count DESC, entry_name;
```
Non-swap safety :
```sql
SELECT
de.event_kind,
ce.event_family,
COUNT(*) AS decoded_count,
COUNT(te.id) AS trade_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_dex_event_coverage_entries ce
ON ce.decoder_code = 'raydium_amm_v4'
AND ce.local_event_kind = de.event_kind
LEFT JOIN k_sol_trade_events te
ON te.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
GROUP BY de.event_kind, ce.event_family
HAVING ce.event_family <> 'swap'
AND COUNT(te.id) > 0
ORDER BY trade_count DESC, de.event_kind;
```
## Livrables attendus
@@ -181,6 +373,7 @@ docs/DEX_DECODER_MATRIX.md
docs/DEX_EVENT_COVERAGE_MATRIX.md
docs/DB_EVENT_MODEL_REVIEW.md
docs/reports/RAYDIUM_AMM_V4_EVENT_COVERAGE_REPORT.md
docs/reports/RAYDIUM_POOL_V4_DECISION_NOTE.md
validation_sql/SQL_VALIDATION_RAYDIUM_AMM_V4_0_7_51.sql
```

View File

@@ -0,0 +1,626 @@
<!-- file: docs/prompts/PROMPT_REPRISE_khadhroony-bobobot_0.7.52-raydium-stable.md -->
# Prompt de reprise — `khadhroony-bobobot` — `0.7.52 raydium_stable_swap`
Reprise du projet `khadhroony-bobobot` après clôture de `0.7.51 raydium_amm_v4`.
## Archive de départ
Utiliser la dernière archive complète du workspace intégrant les deltas validés jusquà :
```text
0.7.51-raydium-amm-v4-final
```
Joindre aussi les docs et SQL de validation à jour :
```text
README.md
ROADMAP.md
CHANGELOG.md
docs/DEX_DECODER_MATRIX.md
docs/DEX_EVENT_COVERAGE_MATRIX.md
docs/DB_EVENT_MODEL_REVIEW.md
docs/reports/RAYDIUM_AMM_V4_EVENT_COVERAGE_REPORT.md
docs/reports/RAYDIUM_POOL_V4_DECISION_NOTE.md
docs/VALIDATION_STATUS_0_7_51_FINAL.md
validation_sql/SQL_VALIDATION_RAYDIUM_AMM_V4_0_7_51.sql
```
## État validé avant reprise
`0.7.51` a clôturé `raydium_amm_v4`.
Validation locale finale rapportée :
```text
cargo test -p kb_lib
405 passed / 0 failed
cargo clippy -p kb_lib --all-targets -- -D warnings
OK
```
Dernier replay local `0.7.51` :
```text
195 replayed
0 decode skipped
195 ledger upserts
70 unsafe ledger rows
168 trades
7 liquidity
15 lifecycle
0 tokenAccount
668 candle upserts
instructionObservations = 2599
resetDeleted = 1578
catalog = 61 tokens / 65 pools / 65 pairs
```
Points de clôture AMM v4 à préserver :
```text
raydium_amm_v4.swap legacy = vide
decoded without coverage entry = vide
instruction_observations > 1 octet = vide
non-swap -> trade = vide
failed tx -> trade = vide
unexplained successful non-materialized events = vide
multi-target materialization = vide
pre_initialize lifecycle audit = 7 / 7
migrate_to_open_book = orderbook only
simulate_info = decoded-only
raydium_pool_v4 = audit-only / pas de decoder autonome
```
## Décision de reprise
Ouvrir une nouvelle tranche :
```text
0.7.52 raydium_stable_swap
```
Code local canonique :
```text
raydium_stable_swap
```
Program id canonique à utiliser comme hypothèse de départ :
```text
5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h
```
Important : upstream Git/IDL/Solscan est un indice, pas une preuve métier. Le program id doit être confirmé par corpus local via `k_sol_instruction_observations`, decoded events, coverage entries et absence de fallback upstream.
## Nouvelle base de travail
Démarrer `0.7.52` sur une base SQLite vide dédiée.
Avant le replay de validation complet, construire volontairement un corpus initial :
```text
1. Demo3 program_id = 5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h
2. Solscan non filtré + essais instruction=<DISCRIMINATOR>
3. backfill Demo2 de signatures contenant des instructions stable swap variées
4. backfill de pools stable swap quand Demo3/Solscan fournit un AMM/pool account fiable
```
Ne pas interpréter labsence de résultat Solscan comme absence on-chain définitive.
## Note Solscan importante
Pour `raydium_stable_swap`, il semble que Solscan ne dispose pas dun Program IDL exploitable sur :
```text
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h#programIdl
```
Donc le filtrage Solscan par instruction peut ne pas fonctionner avec les discriminants 8 octets Carbon/Pinax.
Il faut tester deux approches :
```text
1. Liens exploratoires courts : instruction=00, 01, 02, ...
2. Liens discriminants upstream 8 octets : instruction=<DISCRIMINATOR_HEX>
```
Solscan est une aide de découverte uniquement. La preuve métier reste locale : signatures backfillées, decoded events, instruction observations et coverage DB.
## Sources Git/IDL à utiliser systématiquement
Sources globales :
```text
https://github.com/sevenlabs-hq/carbon/tree/main/decoders
https://github.com/0xfnzero/solana-streamer
https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl
https://github.com/0xfnzero/sol-parser-sdk/tree/main/idls
https://github.com/pinax-network/substreams-solana-idls/tree/main/src
https://github.com/hodlwarden/solana-tx-parser/tree/main/src
https://docs.vybenetwork.com/docs/available-dexs-amms
```
Sources spécifiques `raydium_stable_swap` à vérifier en priorité :
```text
https://github.com/sevenlabs-hq/carbon/tree/main/decoders/raydium-stable-swap-decoder
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/stable
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/stable/idl.json
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/stable/instructions.rs
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/stable/events.rs
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/stable/accounts.rs
```
## Solscan — liens exploratoires
Base non filtrée :
```text
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?hide_spam=false&hide_failed=false&show_related=true&sort=desc
```
Base non filtrée sans related :
```text
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?hide_spam=false&hide_failed=false&show_related=false&sort=desc
```
### Essais courts `instruction=00..11`
Ces liens sont exploratoires. Ils ne prouvent pas que le program utilise des discriminants 1 octet ; ils servent seulement à tester le comportement Solscan quand aucun IDL nest présent.
```text
instruction=00
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=00&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=01
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=01&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=02
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=02&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=03
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=03&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=04
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=04&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=05
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=05&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=06
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=06&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=07
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=07&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=08
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=08&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=09
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=09&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=0a
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=0a&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=0b
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=0b&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=0c
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=0c&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=0d
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=0d&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=0e
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=0e&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=0f
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=0f&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=10
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=10&hide_spam=false&hide_failed=false&show_related=false&sort=desc
instruction=11
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=11&hide_spam=false&hide_failed=false&show_related=false&sort=desc
```
### Essais discriminants 8 octets Carbon/Pinax
À tester aussi, mais ne pas bloquer si Solscan ne filtre rien.
```text
initialize / afaf6d1f0d989bed
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=afaf6d1f0d989bed&hide_spam=false&hide_failed=false&show_related=false&sort=desc
pre_initialize / ff5c572dc6acec02
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=ff5c572dc6acec02&hide_spam=false&hide_failed=false&show_related=false&sort=desc
deposit / f223c68952e1f2b6
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=f223c68952e1f2b6&hide_spam=false&hide_failed=false&show_related=false&sort=desc
withdraw / b712469c946da122
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=b712469c946da122&hide_spam=false&hide_failed=false&show_related=false&sort=desc
swap_base_in / 2aec48a2f2182754
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=2aec48a2f2182754&hide_spam=false&hide_failed=false&show_related=false&sort=desc
swap_base_out / a3d29bd0af92d596
https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h?instruction=a3d29bd0af92d596&hide_spam=false&hide_failed=false&show_related=false&sort=desc
```
## Instructions/discriminants de départ à couvrir
À partir de Carbon stable swap, à vérifier contre Pinax :
```text
initialize afaf6d1f0d989bed pool_create / k_sol_pool_lifecycle_events
pre_initialize ff5c572dc6acec02 pool_create deprecated/partial / k_sol_pool_lifecycle_events si pool context suffisant
deposit f223c68952e1f2b6 liquidity_add / k_sol_liquidity_events
withdraw b712469c946da122 liquidity_remove / k_sol_liquidity_events
swap_base_in 2aec48a2f2182754 swap / k_sol_trade_events
swap_base_out a3d29bd0af92d596 swap / k_sol_trade_events
```
Si Pinax expose des discriminants numériques ou une ABI non Anchor, ne pas forcer les discriminants 8 octets. Le decoder local doit suivre le layout prouvé par corpus local.
## Objectif `0.7.52` — `raydium_stable_swap`
Reprendre Raydium Stable Swap au même niveau de couverture que CPMM/CLMM/AMM v4 :
```text
initialize / pre_initialize
pool lifecycle / pool_create
deposit / withdraw
swap_base_in / swap_base_out
fees / admin/config si présents dans IDL/events/accounts
OpenBook/Serum side effects documentés si présents
side effects SPL Token / Token-2022 documentés mais non promus comme raydium_stable_swap.* directs
fallback instruction_audit nettoyé quand une entrée locale spécialisée couvre linstruction
coverage entries synchronisées et rafraîchies
decoded-only explicitement expliqué quand la matérialisation métier est impossible
```
## Règles fixes
```text
Rust 2024
pas de mod.rs
fichiers Rust avec // file: ...
pas de anyhow
pas de thiserror
pas de ? / unwrap / expect dans kb_lib applicatif
match / if let Err / let Err = ... else
rustdoc sur API publique
re-exports db.rs puis lib.rs si DB modifiée
```
## Invariants métier
```text
non-trade event = jamais trade/candle
failed transaction = audit-only / jamais matérialisée métier
upstream Git/IDL/Solscan = indice, pas preuve métier
program id upstream non promu sans corpus local
side effects SPL Token / Token-2022 restent transversaux sauf preuve multi-DEX et décision DB
instruction_audit et upstream_git.instruction_match doivent être nettoyés quand une entrée locale spécialisée couvre le discriminant
observed_count ne doit pas obligatoirement égaler materialized_count
règle de clôture : observed_count = materialized_count + decoded_only_explained_count + failed_count
```
## Workflow conseillé
1. Créer une nouvelle base SQLite dédiée `0.7.52`.
2. Inventorier Carbon + Pinax pour `raydium_stable_swap`.
3. Vérifier explicitement le program id `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`.
4. Vérifier si les discriminants sont 8 octets Anchor-like, 1 octet, ou autre layout.
5. Synchroniser `k_sol_dex_event_coverage_entries` avec `decoder_code = raydium_stable_swap`.
6. Utiliser Solscan seulement comme aide exploratoire ; si le filtre instruction échoue, utiliser Demo3 program_id + signatures récentes/non filtrées.
7. Backfill Demo2 signature/pool sur corpus varié.
8. Replay local avec :
```text
skipDexDecode = no
forceDexDecode = yes
deferInstructionObservations = yes
```
9. Vérifier :
```text
coverage listed/observed/materialized
residual instruction_audit
residual upstream_git.instruction_match
decoded without coverage entry
failed tx materialization = 0
non-trade trade_count = 0
single-target materialization
trade/candle only for swap events validés
decoded-only explanations
```
## SQL de contrôle minimal `0.7.52`
Coverage stable swap :
```sql
SELECT
entry_name,
entry_kind,
event_family,
expected_db_target,
proof_status,
local_event_kind,
discriminator_hex,
observed_count,
materialized_count,
trade_count
FROM k_sol_dex_event_coverage_entries
WHERE decoder_code = 'raydium_stable_swap'
ORDER BY entry_kind, entry_name, discriminator_hex;
```
Instruction observations :
```sql
SELECT
instruction_name,
discriminator_hex,
COUNT(*) AS observed_count,
COUNT(DISTINCT signature) AS tx_count
FROM k_sol_instruction_observations
WHERE decoder_code = 'raydium_stable_swap'
GROUP BY instruction_name, discriminator_hex
ORDER BY observed_count DESC, instruction_name, discriminator_hex;
```
Residual audit :
```sql
SELECT
json_extract(payload_json, '$.discriminatorHex') AS discriminator_hex,
COUNT(*) AS audit_count,
COUNT(DISTINCT transaction_id) AS tx_count
FROM k_sol_dex_decoded_events
WHERE protocol_name = 'raydium_stable_swap'
AND event_kind = 'raydium_stable_swap.instruction_audit'
GROUP BY discriminator_hex
ORDER BY audit_count DESC, discriminator_hex;
```
Fallback upstream :
```sql
SELECT
json_extract(ug.payload_json, '$.upstreamDecoderCode') AS upstream_decoder_code,
json_extract(ug.payload_json, '$.upstreamEntryName') AS entry_name,
json_extract(ug.payload_json, '$.upstreamDiscriminatorHex') AS discriminator_hex,
json_extract(ug.payload_json, '$.upstreamSourceRepo') AS source_repo,
COUNT(*) AS fallback_count,
COUNT(DISTINCT ug.transaction_id) AS tx_count
FROM k_sol_dex_decoded_events ug
JOIN k_sol_dex_event_coverage_entries ce
ON ce.decoder_code = json_extract(ug.payload_json, '$.upstreamDecoderCode')
AND ce.entry_name = json_extract(ug.payload_json, '$.upstreamEntryName')
AND ce.discriminator_hex = json_extract(ug.payload_json, '$.upstreamDiscriminatorHex')
AND ce.local_event_kind IS NOT NULL
AND ce.local_event_kind <> ''
WHERE ug.protocol_name = 'upstream_git'
AND ug.event_kind = 'upstream_git.instruction_match'
AND json_extract(ug.payload_json, '$.upstreamDecoderCode') = 'raydium_stable_swap'
GROUP BY upstream_decoder_code, entry_name, discriminator_hex, source_repo
ORDER BY fallback_count DESC, entry_name;
```
Non-swap safety :
```sql
SELECT
de.event_kind,
ce.event_family,
COUNT(*) AS decoded_count,
COUNT(te.id) AS trade_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_dex_event_coverage_entries ce
ON ce.decoder_code = 'raydium_stable_swap'
AND ce.local_event_kind = de.event_kind
LEFT JOIN k_sol_trade_events te
ON te.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_stable_swap'
GROUP BY de.event_kind, ce.event_family
HAVING ce.event_family <> 'swap'
AND COUNT(te.id) > 0
ORDER BY trade_count DESC, de.event_kind;
```
Failed tx safety :
```sql
SELECT
de.event_kind,
COUNT(*) AS decoded_failed_count,
COUNT(te.id) AS trade_count
FROM k_sol_dex_decoded_events de
JOIN k_sol_chain_transactions tx
ON tx.id = de.transaction_id
LEFT JOIN k_sol_trade_events te
ON te.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_stable_swap'
AND tx.err_json IS NOT NULL
AND tx.err_json <> ''
AND tx.err_json <> 'null'
GROUP BY de.event_kind
HAVING COUNT(te.id) > 0
ORDER BY trade_count DESC, de.event_kind;
```
Decoded without coverage :
```sql
SELECT
de.event_kind,
COUNT(*) AS decoded_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_dex_event_coverage_entries ce
ON ce.decoder_code = 'raydium_stable_swap'
AND ce.local_event_kind = de.event_kind
WHERE de.protocol_name = 'raydium_stable_swap'
AND ce.id IS NULL
GROUP BY de.event_kind
ORDER BY decoded_count DESC, de.event_kind;
```
Multi-target materialization :
```sql
SELECT
de.event_kind,
COUNT(DISTINCT de.id) AS decoded_count,
COUNT(DISTINCT te.id) AS trade_count,
COUNT(DISTINCT le.id) AS liquidity_count,
COUNT(DISTINCT pe.id) AS lifecycle_count,
COUNT(DISTINCT fe.id) AS fee_count,
COUNT(DISTINCT ae.id) AS admin_count,
COUNT(DISTINCT oe.id) AS orderbook_count,
(
CASE WHEN COUNT(DISTINCT te.id) > 0 THEN 1 ELSE 0 END
+ CASE WHEN COUNT(DISTINCT le.id) > 0 THEN 1 ELSE 0 END
+ CASE WHEN COUNT(DISTINCT pe.id) > 0 THEN 1 ELSE 0 END
+ CASE WHEN COUNT(DISTINCT fe.id) > 0 THEN 1 ELSE 0 END
+ CASE WHEN COUNT(DISTINCT ae.id) > 0 THEN 1 ELSE 0 END
+ CASE WHEN COUNT(DISTINCT oe.id) > 0 THEN 1 ELSE 0 END
) AS materialized_target_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_trade_events te
ON te.decoded_event_id = de.id
LEFT JOIN k_sol_liquidity_events le
ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pool_lifecycle_events pe
ON pe.decoded_event_id = de.id
LEFT JOIN k_sol_fee_events fe
ON fe.decoded_event_id = de.id
LEFT JOIN k_sol_pool_admin_events ae
ON ae.decoded_event_id = de.id
LEFT JOIN k_sol_orderbook_events oe
ON oe.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_stable_swap'
GROUP BY de.event_kind
HAVING materialized_target_count > 1
ORDER BY materialized_target_count DESC, de.event_kind;
```
Unexplained successful non-materialized events :
```sql
SELECT
de.event_kind,
COUNT(*) AS unexplained_count
FROM k_sol_dex_decoded_events de
JOIN k_sol_chain_transactions tx
ON tx.id = de.transaction_id
LEFT JOIN k_sol_trade_events te
ON te.decoded_event_id = de.id
LEFT JOIN k_sol_liquidity_events le
ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pool_lifecycle_events pe
ON pe.decoded_event_id = de.id
LEFT JOIN k_sol_fee_events fe
ON fe.decoded_event_id = de.id
LEFT JOIN k_sol_pool_admin_events ae
ON ae.decoded_event_id = de.id
LEFT JOIN k_sol_orderbook_events oe
ON oe.decoded_event_id = de.id
LEFT JOIN k_sol_token_account_events tae
ON tae.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_stable_swap'
AND (
tx.err_json IS NULL
OR tx.err_json = ''
OR tx.err_json = 'null'
)
AND te.id IS NULL
AND le.id IS NULL
AND pe.id IS NULL
AND fe.id IS NULL
AND ae.id IS NULL
AND oe.id IS NULL
AND tae.id IS NULL
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipTradeReason')), '') = ''
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipLiquidityReason')), '') = ''
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipLifecycleReason')), '') = ''
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipCatalogReason')), '') = ''
GROUP BY de.event_kind
ORDER BY unexplained_count DESC, de.event_kind;
```
Materialization summary :
```sql
SELECT
de.event_kind,
COUNT(DISTINCT de.id) AS decoded_count,
COUNT(DISTINCT te.id) AS trade_count,
COUNT(DISTINCT le.id) AS liquidity_count,
COUNT(DISTINCT pe.id) AS lifecycle_count,
COUNT(DISTINCT fe.id) AS fee_count,
COUNT(DISTINCT ae.id) AS admin_count,
COUNT(DISTINCT oe.id) AS orderbook_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_trade_events te
ON te.decoded_event_id = de.id
LEFT JOIN k_sol_liquidity_events le
ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pool_lifecycle_events pe
ON pe.decoded_event_id = de.id
LEFT JOIN k_sol_fee_events fe
ON fe.decoded_event_id = de.id
LEFT JOIN k_sol_pool_admin_events ae
ON ae.decoded_event_id = de.id
LEFT JOIN k_sol_orderbook_events oe
ON oe.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_stable_swap'
GROUP BY de.event_kind
ORDER BY de.event_kind;
```
## Livrables attendus
```text
archive delta fichiers modifiés/ajoutés
README.md / ROADMAP.md / CHANGELOG.md mis à jour
docs/DEX_DECODER_MATRIX.md
docs/DEX_EVENT_COVERAGE_MATRIX.md
docs/DB_EVENT_MODEL_REVIEW.md
docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md
validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql
```
Validation finale locale :
```bash
cargo fmt
cargo test -p kb_lib
cargo clippy -p kb_lib --all-targets -- -D warnings
```
## Critères de clôture `0.7.52`
```text
tous les discriminants stable swap connus sont listés en coverage
tous les discriminants stable swap connus sont observés localement ou explicitement marqués mapped_unverified
instruction_audit résiduel vide pour les discriminants couverts
fallback upstream_git.instruction_match résiduel vide pour les discriminants couverts
decoded without coverage vide
non-swap -> trade vide
failed tx -> trade vide
multi-target materialization vide
successful decoded-only events expliqués par skip*Reason
trade/candle uniquement pour swaps avec montants fiables
deposit/withdraw uniquement vers liquidity
initialize/pre_initialize uniquement vers lifecycle
simulate/transport éventuel reste decoded-only sauf preuve métier
```