v0.1.0-pre.073

This commit is contained in:
2026-07-31 19:34:00 +02:00
parent 3b1ded6909
commit 5e1ad759d8
148 changed files with 14056 additions and 18 deletions

View File

@@ -0,0 +1,130 @@
<!-- file: docs/reports/DEX_COVERAGE_GLOBAL_WATCHLIST_0_7_53.md -->
# DEX coverage global watchlist — `0.7.53`
## Objet
Ce rapport accompagne la clôture `0.7.53 pump_swap`. Il sépare les anomalies bloquantes des files de travail futures.
`pump_swap` est clos côté transaction/log decoder et matérialisation métier. Les lignes restantes de surveillance globale ne sont pas des erreurs PumpSwap.
## Résultat de clôture PumpSwap
Validation rapportée :
```text
cargo test -p kb_lib -> 421 passed / 0 failed
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
```
Replay élargi rapporté :
```text
1189 replayed
0 decode skipped
1189 ledger upserts
967 unsafe ledger rows
928 trades
13 liquidity
8 lifecycle
0 tokenAccount
3700 candle upserts
instructionObservations = 25724
resetDeleted = 5622
catalog = 76 tokens / 80 pools / 80 pairs
```
Checks PumpSwap attendus vides :
- decoded events sans coverage ;
- fallback `upstream_git` couvert localement ;
- successful trade candidates sans trade et sans raison explicite ;
- failed transaction matérialisée en business trade ;
- non-swap matérialisé en trade ;
- multi-target materialization.
`buy_exact_quote_in` :
```text
pump_swap_anchor_buy_event -> 168 decoded / 167 trades / 1 failed tx
instruction_bounds_only -> decoded-only, sans trade
```
## Non-régression Raydium
Les checks ciblés Raydium AMM v4 / CLMM / CPMM normalisés sont vides. Il n'y a pas de correction Raydium à inclure dans `0.7.53`.
Lecture correcte :
- `raydium_amm_v4.swap_base_in_v2` : observé et matérialisé dans le corpus courant ;
- `raydium_clmm.swap_v2` : observé et matérialisé dans le corpus courant ;
- `raydium_cpmm.swap_base_input` : observé et matérialisé dans le corpus courant ;
- les entrées `upstream_git_mapped_unverified` avec `observed_count=0` sont des entrées registry non observées, pas des régressions.
## Gaps locaux reportés
La requête globale `local decoded events without coverage` retourne des gaps Meteora connus et reportés :
```text
meteora_dlmm.swap
meteora_damm_v2.instruction_audit
meteora_damm_v2.swap
```
Décision : ne pas les corriger dans `0.7.53`. Ils seront repris dans les tranches Meteora futures.
## Backlog upstream observé
La file `upstream_git.instruction_match` indique les prochaines surfaces à prioriser. Au moment de la clôture :
| Priorité | Surface | Indice principal | Décision |
|---:|---|---|---|
| 1 | `pump_fees` | `get_fees` très fréquent | Prochaine tranche recommandée ; aucun trade/candle direct attendu. |
| 2 | `pump_fun` | creator fees, migrate, set/admin creator | Tranche launch/bonding séparée. |
| 3 | `jupiter_swap` | `route_v2`, `create_token_account`, `route` | Agrégateur/router ; éviter double-count DEX effectifs. |
| 4 | `dflow_aggregator_v4`, `onchain_labs_dex_v2` | swaps/route helpers | Surfaces secondaires après Pump/Meteora. |
| 5 | `orca_whirlpools` | faibles occurrences | À reprendre plus tard avec corpus dédié. |
## Observations non attribuées
Les observations avec `decoder_code` vide ne doivent pas être traitées comme des discriminants Anchor confirmés. Elles exigent d'abord :
1. inspection de `sample_signature` ;
2. extraction du `program_id` effectif ;
3. comparaison aux IDL locales `idls/` et aux sources Git ;
4. ajout d'un decoder ou d'un statut explicite seulement si le programme est identifié.
## Source IDL locale
Le répertoire `idls/` est désormais une source locale de savoir. Les IDL téléchargées depuis Solscan doivent être utilisées en plus des liens Git, avec la règle suivante : une IDL donne une surface possible, mais la matérialisation métier exige corpus, replay et SQL.
## Vérification `raydium_pool_v4.json`
Fichier Git vérifié : `0xfnzero/sol-parser-sdk/idls/raydium_pool_v4.json`.
Constats :
- la page GitHub annonce `3400` lignes / environ `101 KB` ;
- le fichier expose notamment `swapBaseIn`, `addLiquidity` et des comptes OpenBook/Serum (`OpenBookMarket`, `OpenBookBids`, `OpenBookAsks`, etc.) ;
- la chaîne du program id AMM v4 `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` n'apparaît pas dans la page GitHub consultée ;
- aucun fichier local `idls/raydium_*.json` ne porte le nom `raydium_pool_v4` ;
- les fichiers Raydium locaux présents sont `raydium_clmm`, `raydium_cpmm`, `raydium_launchlab` et `raydium_lock`.
Table locale :
| Fichier local | Name IDL | Address IDL | Taille | SHA-256 |
|---|---|---|---:|---|
| `idls/raydium_clmm.CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK.json` | `raydium_clmm` | `CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK` | 86240 | `d3f265adc9e4d7b1a28641444800a60bcdeb921ef136855fe8dea4532afa18bd` |
| `idls/raydium_cpmm.CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C.json` | `raydium_cp_swap` | `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C` | 32066 | `5b709dfe7b0df67c9e29655307ae877244d3bb8022056ee01c754f0e36264d9c` |
| `idls/raydium_launchlab.LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj.json` | `raydium_launchpad` | `LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj` | 68052 | `c1465a10f38912413f55f04a68536c989992add1b3d48cba86dca97212a482da` |
| `idls/raydium_lock.LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE.json` | `raydium_liquidity_locking` | absent | 10621 | `da45fd5eaf726e5e2ead7280c04588ebd4224d203304cdc8217b012b8130e1f1` |
Décision : `raydium_pool_v4.json` ne correspond à aucun fichier JSON local actuel. Il reste une source annexe d'audit AMM v4/strategy/wrapper à traiter plus tard, sans bloquer `0.7.53`.
## SQL associé
Voir :
```text
validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql
```

View File

@@ -0,0 +1,151 @@
<!-- file: docs/reports/FEE_EVENT_AMOUNTS_MODEL_NOTE_0_7_56.md -->
# Note technique — `k_sol_fee_event_amounts` et policy fees — `0.7.56`
## Objectif
La table `k_sol_fee_events` était suffisante pour un fee mono-montant, mais insuffisante pour les cas multi-mint, multi-destination ou multi-composant. `0.7.56` ajoute donc `k_sol_fee_event_amounts` comme table de legs rattachée au parent fee.
## Modèle
```text
k_sol_fee_events
id
transaction_id
decoded_event_id
fee_token_mint nullable / vide si multi-leg
fee_amount_raw nullable / vide si multi-leg
payload_json
k_sol_fee_event_amounts
id
fee_event_id
transaction_id
decoded_event_id
leg_index
fee_component_kind
token_mint
amount_raw
source_account
destination_account
amount_source
payload_json
```
## Règles invariantes
1. Un parent fee scalaire avec `fee_token_mint + fee_amount_raw` doit toujours avoir un leg `0`.
2. Un parent multi-leg ou multi-mint ne doit pas agréger artificiellement ses montants dans le parent.
3. Les legs doivent pointer vers le même `transaction_id` et `decoded_event_id` que le parent.
4. Les legs doivent être supprimés/remplacés lors du replay/cleanup parent.
5. Les transactions failed ne doivent pas créer de parent ou leg fee métier.
6. Les bornes d'instruction (`maxAmount`, `minAmount`, `u64::MAX`) ne sont pas des montants exécutés.
## Sources de montant acceptées
| `amount_source` | Usage |
|---|---|
| `parent_fee_event_amount` | Leg généré automatiquement depuis un parent scalaire déjà fiable. |
| `fee_event_amounts` | Source explicite reconstruite par un matérialisateur spécialisé. |
| `inner_spl_transfer` | CPI SPL vérifié dans un matérialisateur spécialisé. |
| `lamport_balance_delta` | Delta lamports prouvé et contextualisé. |
| `allowlisted_inner_spl_transfer` | Recovery générique mais strictement allowlistée pour event kinds déjà validés. |
## Recovery allowlistée
La recovery `allowlisted_inner_spl_transfer` n'est pas une règle globale. Elle s'applique seulement aux event kinds explicitement autorisés dans le code. Cette restriction protège les futurs décodeurs : une nouvelle surface ne doit jamais créer des legs fee à partir de transferts internes tant que la sémantique n'a pas été inspectée.
Résultats de validation croisée en `0.7.56` :
| Base / surface | Effet observé |
|---|---|
| `meteora_dbc` | Aucun usage de l'allowlist générique ; chemins spécialisés DBC conservés. |
| `raydium_launchpad` | `212` parents enrichis en legs : `claim_creator_fee`, `claim_platform_fee`, `claim_platform_fee_from_vault`, `collect_fee`. |
| `raydium_cpmm` | `collect_creator_fee` enrichi ; `collect_fund_fee` / `collect_protocol_fee` explicités sans transfert exploitable. |
| `pump_swap` | `collect_coin_creator_fee` et un `transfer_creator_fees_to_pump_v2` enrichis ; autres cas zero/no-transfer explicités. |
| `pump_fees` | `crank_donation_fee_pda` et `sweep_buyback` enrichis ; events déjà scalaires conservés. |
## Contrôles SQL obligatoires
### Parent scalaire sans leg
```sql
SELECT
de.protocol_name,
de.event_kind,
tx.signature,
fee.id AS fee_event_id,
fee.fee_token_mint,
fee.fee_amount_raw,
fee.payload_json
FROM k_sol_fee_events fee
JOIN k_sol_dex_decoded_events de
ON de.id = fee.decoded_event_id
JOIN k_sol_chain_transactions tx
ON tx.id = fee.transaction_id
LEFT JOIN k_sol_fee_event_amounts fea
ON fea.fee_event_id = fee.id
WHERE COALESCE(TRIM(fee.fee_token_mint), '') <> ''
AND COALESCE(TRIM(fee.fee_amount_raw), '') <> ''
AND fea.id IS NULL
ORDER BY
de.protocol_name,
de.event_kind,
tx.signature
LIMIT 100;
```
Attendu : vide.
### Legs orphelins
```sql
SELECT
fea.id,
fea.fee_event_id,
fea.transaction_id,
fea.decoded_event_id
FROM k_sol_fee_event_amounts fea
LEFT JOIN k_sol_fee_events fee
ON fee.id = fea.fee_event_id
WHERE fee.id IS NULL;
```
Attendu : vide.
### Résumé parent/legs par event
```sql
SELECT
de.protocol_name,
de.event_kind,
COUNT(DISTINCT fee.id) AS fee_parent_count,
COUNT(DISTINCT CASE
WHEN COALESCE(TRIM(fee.fee_token_mint), '') <> ''
AND COALESCE(TRIM(fee.fee_amount_raw), '') <> ''
THEN fee.id
ELSE NULL
END) AS parent_with_scalar_amount_count,
COUNT(DISTINCT fea.id) AS fee_amount_leg_count,
MIN(tx.signature) AS sample_signature
FROM k_sol_fee_events fee
JOIN k_sol_dex_decoded_events de
ON de.id = fee.decoded_event_id
JOIN k_sol_chain_transactions tx
ON tx.id = fee.transaction_id
LEFT JOIN k_sol_fee_event_amounts fea
ON fea.fee_event_id = fee.id
GROUP BY
de.protocol_name,
de.event_kind
ORDER BY
de.protocol_name,
de.event_kind;
```
## Règles pour `0.7.57 meteora_dlmm`
- Les instructions `claim_fee`, `claim_fee2`, `withdraw_protocol_fee`, `zap_protocol_fee`, `CompositionFee`, `ClaimFee`, `ClaimFee2` doivent utiliser `k_sol_fee_event_amounts` dès qu'un montant/mint fiable est disponible.
- Les rewards (`claim_reward*`, `fund_reward`, `withdraw_ineligible_reward`) vont vers `k_sol_reward_events`, pas vers fees, sauf sémantique contraire prouvée.
- Les `composition_fee` de swap/liquidity ne doivent pas être double-comptés si déjà inclus dans le trade/liquidity effectif.
- Toute recovery générique doit être déclarée par policy explicite et tests synthétiques ; ne pas ajouter DLMM à l'allowlist sans audit par event kind.

View File

@@ -0,0 +1,161 @@
<!-- file: docs/reports/METEORA_DBC_EVENT_COVERAGE_REPORT.md -->
# Meteora DBC Event Coverage Report — `0.7.56 final`
## Statut final
La tranche `0.7.56 meteora_dbc` est clôturée.
Program id :
```text
dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN
```
Source locale prioritaire :
```text
idls/meteora_dbc.dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN.json
```
Surface IDL : `28` instructions, `23` events Anchor, `9` accounts, `59` types.
## Résultat build/replay final
```text
cargo test -p kb_lib -> 446 passed / 0 failed
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
480 replayed
0 decode skipped
480 ledger upserts
454 unsafe ledger rows
264 trades
1 liquidity
122 lifecycle
0 tokenAccount
1056 candle upserts
instructionObservations = 7167
resetDeleted = 3583
catalog = 86 tokens / 60 pools / 60 pairs
```
Replay final recommandé pour reproduire :
```text
skipDexDecode=no
forceDexDecode=yes
deferInstructionObservations=yes
```
## Décisions métier verrouillées
### Swaps
- `meteora_dbc.swap` et `meteora_dbc.swap2` sont les seules entrées candidates trade/candle directes.
- Les trades/candles ne sont produits que si les montants exécutés et les mints base/quote sont fiables.
- Les montants de `swap2` doivent être dérivés du layout et/ou des CPI SPL effectifs ; ne pas utiliser naïvement les bornes d'instruction.
- Les events Anchor `EvtSwap` / `EvtSwap2` restent decoded-only s'ils ne portent pas un contexte mint/pair suffisant ou s'ils doublonnent l'instruction matérialisée.
### Lifecycle / migration / lockers
- `initialize_virtual_pool_with_spl_token` et `initialize_virtual_pool_with_token2022` alimentent lifecycle/catalog lorsque les comptes pool/base/quote/config sont fiables.
- `create_locker`, `migrate_meteora_damm_claim_lp_token`, `migrate_meteora_damm_lock_lp_token`, `migration_damm_v2*` et `migrate_meteora_damm*` sont lifecycle, pas liquidity artificielle.
- Les metadata-only restent decoded-only avec raison explicite si elles n'apportent pas de cible métier fiable.
### Admin/config
- `create_config`, `create_operator_account`, `close_*operator*`, metadata, `transfer_pool_creator` et events config/admin alimentent `k_sol_pool_admin_events` uniquement si l'acteur et la cible sont fiables.
- Les payloads génériques ou incomplets restent audit/decoded-only.
### Fees
- Les fees DBC utilisent le modèle parent+legs : `k_sol_fee_events` + `k_sol_fee_event_amounts`.
- Les maxima d'instruction (`maxAmount*`, `u64::MAX`, bornes de claim) ne sont pas des montants exécutés.
- Les montants fiables proviennent des CPI SPL, des legs explicitement reconstruits ou des lamport balance deltas prouvés.
- Les events Anchor fee sans mint restent decoded-only avec `skipFeeReason`.
- Les cas sans transfert réel portent `fee_instruction_has_no_actual_transfer` ou `fee_instruction_has_only_zero_amount_transfers`.
## Matérialisation fee finale
| Event kind | Fee parents | Parents scalaires | Amount legs | Décision |
|---|---:|---:|---:|---|
| `meteora_dbc.claim_creator_trading_fee` | 8 | 8 | 8 | Mono-leg fiable. |
| `meteora_dbc.claim_partner_pool_creation_fee` | 10 | 10 | 10 | Mono-leg fiable. |
| `meteora_dbc.claim_protocol_fee` | 10 | 10 | 10 | Mono-leg fiable. |
| `meteora_dbc.claim_protocol_pool_creation_fee` | 10 | 10 | 10 | Mono-leg/lamport delta fiable. |
| `meteora_dbc.claim_trading_fee` | 11 | 6 | 18 | Mix mono-leg et multi-leg ; parent non agrégé pour multi-leg. |
| `meteora_dbc.creator_withdraw_surplus` | 2 | 2 | 2 | Mono-leg fiable ; résiduels sans transfert réel explicités. |
| `meteora_dbc.partner_withdraw_surplus` | 9 | 9 | 9 | Mono-leg fiable. |
| `meteora_dbc.withdraw_leftover` | 10 | 10 | 10 | Mono-leg fiable. |
| `meteora_dbc.withdraw_migration_fee` | 9 | 9 | 9 | Fee, pas migration target ; mono-leg fiable. |
| `meteora_dbc.zap_protocol_fee` | 10 | 10 | 10 | Mono-leg fiable. |
| **Total `meteora_dbc`** | **89** | n/a | **96** | Parent+legs validé. |
## Socle `k_sol_fee_event_amounts`
La version `0.7.56` ajoute un modèle durable pour les fees composés :
- `k_sol_fee_events` est le parent logique unique lié au `decoded_event_id` ;
- `k_sol_fee_event_amounts` contient les legs de montants, avec `leg_index`, `fee_component_kind`, `token_mint`, `amount_raw`, comptes source/destination et `amount_source` ;
- un parent avec `fee_token_mint + fee_amount_raw` crée automatiquement un leg scalaire ;
- un parent multi-leg/multi-mint laisse les champs scalaires du parent vides et stocke tout dans les legs ;
- les deletes/replays nettoient les legs avant ou avec le parent ;
- la requête de contrôle `parent scalar without leg` doit rester vide.
Sources `amount_source` connues en fin de tranche :
```text
parent_fee_event_amount
fee_event_amounts
inner_spl_transfer
lamport_balance_delta
allowlisted_inner_spl_transfer
```
## Recovery fee allowlistée
La recovery `allowlisted_inner_spl_transfer` est volontairement non globale.
Elle a été testée sur anciennes bases pour enrichir les surfaces déjà connues :
| Surface testée | Résultat |
|---|---|
| `raydium_launchpad` | `claim_creator_fee`, `claim_platform_fee`, `claim_platform_fee_from_vault`, `collect_fee` enrichis en legs depuis CPI SPL. |
| `raydium_cpmm` | `collect_creator_fee` enrichi ; `collect_fund_fee` et `collect_protocol_fee` restent sans transfert réel exploitable dans le corpus testé. |
| `pump_swap` | `collect_coin_creator_fee` et certains `transfer_creator_fees_to_pump_v2` enrichis ; cas zero/no-transfer explicités. |
| `pump_fees` | `crank_donation_fee_pda` et `sweep_buyback` enrichis ; events déjà scalaires conservés. |
| `meteora_dbc` | Non concerné par l'allowlist générique ; DBC conserve ses chemins spécifiques. |
Règle pour les prochaines versions : tout nouveau decoder doit déclarer explicitement sa policy de récupération des montants fee. Aucun futur decoder ne doit hériter automatiquement de la recovery CPI SPL.
## Checks de fermeture
Les contrôles de fermeture exigés sont propres :
- fallback `upstream_git` `meteora_dbc` pour entrées couvertes localement : vide ;
- decoded `meteora_dbc` sans coverage : vide ;
- successful non-materialized sans `skip*Reason` ou policy explicite : vide ;
- failed tx avec materialization métier : vide ;
- multi-target materialization : vide ;
- non-swap DBC vers trade/candle : vide ;
- parent fee scalaire sans leg : vide ;
- legs fee orphelins : vide ;
- watchlist globale sans backlog dominant `meteora_dbc`.
## Fichiers de référence
```text
kb_lib/src/dex/meteora_dbc.rs
kb_lib/src/non_trade_event_materialization.rs
kb_lib/src/db/queries/fee_event_amount.rs
kb_lib/src/db/entities/fee_event_amount.rs
kb_lib/src/db/dtos/fee_event_amount.rs
validation_sql/SQL_VALIDATION_METEORA_DBC_0_7_56.sql
docs/reports/FEE_EVENT_AMOUNTS_MODEL_NOTE_0_7_56.md
docs/VALIDATION_STATUS_0_7_56_FINAL.md
docs/prompts/PROMPT_0_7_57_METEORA_DLMM_FULL_DECODE_MATERIALIZATION.md
```
## Décision
`0.7.56 meteora_dbc` est clôturé. La prochaine tranche est `0.7.57 meteora_dlmm` en full decode + full materialization.

View File

@@ -0,0 +1,182 @@
# Meteora DLMM event coverage report — 0.7.57 final
## Scope
Version `0.7.57` closes `meteora_dlmm` from the local IDL and the dedicated local corpus.
Target program:
```text
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
```
Local IDL:
```text
idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json
```
Final inventoried surface:
```text
76 IDL instructions
30 Anchor events
12 accounts
```
The local corpus additionally identified discriminator `75c73e67068e1fcb` as `initialize_preset_parameter_v2`. This discriminator was not present in the local IDL under that spelling, but the transaction logs contain `Instruction: InitializePresetParameterV2`, the account layout is stable, and the instruction creates a 36-byte DLMM-owned preset parameter account through the system program.
## Final validation summary
```text
cargo test -p kb_lib -> 460 passed / 0 failed
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
769 replayed
0 decode skipped
769 ledger upserts
646 unsafe ledger rows
106 trades
664 liquidity
1107 lifecycle
0 tokenAccount
424 candle upserts
instructionObservations = 8062
resetDeleted = 9898
catalog = 169 tokens / 218 pools / 218 pairs
```
## Closure checks
All blocking checks are clean:
```text
upstream_git fallback for locally covered meteora_dlmm entries -> empty
local instruction_audit observed -> 0
DLMM decoded events without coverage -> empty
successful non-materialized DLMM without explicit skip/policy -> empty
failed transaction business materialization -> empty
multi-target materialization -> empty
non-swap trade/candle safety -> empty
fee parent scalar without fee amount leg -> empty
orphan fee amount legs -> empty
limit/orderbook trade/candle double-count -> empty
logical duplicate coverage rows -> empty
```
The only coverage difference left is explained and non-blocking:
```text
close_bin_array observed 16 / materialized 14
14 successful transactions -> lifecycle materialized
2 failed transactions Custom 6015 -> decoded/audit only, no business materialization
```
## Materialization policy
### Trades and candles
Only instruction-level DLMM swaps can produce trades/candles:
```text
meteora_dlmm.swap
meteora_dlmm.swap2
meteora_dlmm.swap_exact_out
meteora_dlmm.swap_exact_out2
meteora_dlmm.swap_with_price_impact
meteora_dlmm.swap_with_price_impact2
```
Anchor `swap_event` and `swap2_evt` are materialized as lifecycle `swap_log` rows and never as trades/candles. This prevents double-counting when an instruction swap and an Anchor log describe the same user-visible swap.
### Liquidity and lifecycle
The following families are materialized when transactions are successful and context is reliable:
```text
add_liquidity*
remove_liquidity*
remove_all_liquidity
rebalance_liquidity
initialize_bin_array*
close_bin_array
go_to_a_bin*
initialize_position*
close_position*
increase_position_length*
decrease_position_length*
update_position_operator*
lb_pair_create_event
position_create_event
position_close_event
```
Position and bin lifecycle events are routed to `k_sol_pool_lifecycle_events` when the operation is structural rather than a direct liquidity amount delta.
### Fees
Fee parents are written to `k_sol_fee_events`. Amount legs are written to `k_sol_fee_event_amounts`.
Final observed amount-leg summary:
```text
claim_fee 64 parents / 64 legs
claim_fee2 63 parents / 88 legs
claim_fee_event 127 parents / 187 legs
claim_fee2_event 78 parents / 118 legs
composition_fee_event 51 parents / 63 legs
withdraw_protocol_fee 14 parents / 20 legs
zap_protocol_fee 13 parents / 13 legs
```
The inner SPL transfer recovery is explicitly allowlisted for DLMM fee event kinds. It is not inherited globally by future decoders.
### Rewards
Reward parents are written to `k_sol_reward_events`. Amounts are recovered only when a reliable inner SPL transfer or decoded amount is present.
Final observed scalar amount summary:
```text
claim_reward 15 parents / 1 scalar amount
claim_reward2 19 parents / 10 scalar amounts
claim_reward_event 34 parents / 25 scalar amounts
claim_reward2_event 19 parents / 10 scalar amounts
fund_reward 10 parents / 10 scalar amounts
fund_reward_event 10 parents / 10 scalar amounts
initialize_reward 9 parents / 0 amount
initialize_reward_event 9 parents / 0 amount
```
`initialize_reward` and `initialize_reward_event` remain without amount because they are configuration/initialization events, not executed reward transfers. No amount is fabricated from limits, bounds or configuration fields.
### Admin/config and orderbook
Admin/config events materialize to `k_sol_pool_admin_events`. Limit-order operations materialize to `k_sol_orderbook_events` and never to trade/candle tables.
Important promoted local corpus entry:
```text
75c73e67068e1fcb -> meteora_dlmm.initialize_preset_parameter_v2 -> k_sol_pool_admin_events
```
## Remaining non-observed surfaces
Non-observed IDL/account rows remain in coverage with `observed_count = 0` and `materialized_count = 0`. They are not blockers.
Examples:
```text
update_reward_duration
update_reward_funder
withdraw_ineligible_reward
migrate_position
account metadata rows
for_idl_type_generation_do_not_call
anchor_self_cpi_log registry row
```
## Decision
`0.7.57 meteora_dlmm` is closed. Do not add further DLMM Rust patches unless a new corpus proves a successful transaction that is decoded but not materialized and lacks an explicit skip/policy reason.
Next recommended work is not another DLMM patch: implement `0.7.58 sqlite_db_transaction_merger` first, then move `demo4_program_surface_discovery` to `0.7.59`. The merger is required to build a consolidated cross-DEX regression corpus before new surface discovery work.

View File

@@ -0,0 +1,134 @@
<!-- file: docs/reports/PUMP_FEES_EVENT_COVERAGE_REPORT.md -->
# Pump Fees event coverage report — 0.7.55 final
## Portée
Programme cible : `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ`.
Source locale prioritaire : `idls/pump_fees.pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ.json`.
L'IDL locale couvre `29` instructions, `20` events Anchor, `9` accounts et `34` types. La tranche ajoute un decoder local maximal `pump_fees` depuis l'IDL locale, le registre Carbon partiel et les discriminators observés via Solscan/corpus.
## Décisions métier
- `pump_fees` est traité comme programme fee/config/accounting.
- Aucun `k_sol_trade_events` ni candle ne doit être créé pour `pump_fees` sans preuve transactionnelle stricte d'un swap autonome.
- `get_fees` reste decoded-only : il décrit un calcul/preview de fees, pas un paiement réalisé.
- Les claims social fee alimentent `k_sol_reward_events` seulement si transaction OK et montant/acteur/mint exploitables.
- Les flux donation/buyback alimentent `k_sol_fee_events` seulement si transaction OK et montant fiable.
- Les créations/configurations/autorités/tiers alimentent `k_sol_pool_lifecycle_events` ou `k_sol_pool_admin_events` selon classification.
- Les transactions failed restent decoded-only/audit-only.
## Résultat build/test
```text
cargo test -p kb_lib -> 431 passed / 0 failed
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
```
## Replay final rapporté
```text
127 replayed
0 decode skipped
150 ledger upserts
125 unsafe ledger rows
4 trades
0 liquidity
115 lifecycle
0 tokenAccount
16 candle upserts
instructionObservations = 2234
resetDeleted = 1644
catalog = 11 tokens / 10 pools / 10 pairs
```
Les `4 trades` et `16 candle upserts` du replay proviennent d'autres surfaces du corpus local ; le contrôle anti-trade `pump_fees` est vide.
## Coverage local
### Instructions observées et couvertes
| Instruction | Discriminator | Observation principale | Matérialisation |
|---|---:|---:|---|
| `sweep_buyback` | `8a21cc26cfa19fe2` | `96` | `k_sol_fee_events` |
| `create_fee_sharing_config` | `c34e564c6f34fbd5` | `42` observations / `36` decoded | `k_sol_pool_lifecycle_events` |
| `update_fee_shares` | `bd0d8863bba4ed23` | `26` observations / `16` decoded | `k_sol_pool_admin_events` |
| `claim_social_fee_pda_v2` | `114df0863abc3595` | `25` | `k_sol_reward_events` |
| `update_fee_shares_v2` | `6ffb31064e4e6a12` | `19` | `k_sol_pool_admin_events` |
| `claim_social_fee_pda` | `e115fb85a11ec7e2` | `15` observations / `10` decoded | `k_sol_reward_events` |
| `crank_donation_fee_pda` | `dc0abda7a9111945` | `14` | `k_sol_fee_events` |
| `get_fees` | `e7257e55cf5b3f34` | `13` observations / `5` decoded | decoded-only |
| `transfer_fee_sharing_authority` | `ca0a4bc8a422d260` | `12` | `k_sol_pool_admin_events` |
| `initialize_fee_program_global` | `23d78254e9387ca7` | `1` | `k_sol_pool_lifecycle_events` |
Le discriminator `e445a52e51cb9a1d` est classé comme `pump_fees.anchor_self_cpi_log` transport Anchor self-CPI : `271` observations / `119` tx.
### Instructions IDL non observées mais programmées
Ces entrées n'ont pas de signature Solscan/corpus au moment de la clôture, mais restent décodables si des transactions futures apparaissent :
| Instruction | Discriminator | Classification | Target prévu |
|---|---:|---|---|
| `reset_fee_sharing_config_v2` | `a9f511d15e5bf880` | admin_config | `k_sol_pool_admin_events` |
| `set_authority` | `85fa25156ea31a79` | admin_config | `k_sol_pool_admin_events` |
| `set_claim_rate_limit` | `b9d39faed4315804` | audit | decoded-only |
| `set_disable_flags` | `c2d9702372de33be` | admin_config | `k_sol_pool_admin_events` |
| `set_social_claim_authority` | `9336b89a88edb999` | admin_config | `k_sol_pool_admin_events` |
### Anchor events IDL non observés mais testés synthétiquement
| Event Anchor | Discriminator | Statut |
|---|---:|---|
| `SetAuthorityEvent` | `12af8442d0c957f2` | decoder + test synthétique |
| `SetClaimRateLimitEvent` | `0d8f8febb5133328` | decoder + test synthétique |
| `SetDisableFlagsEvent` | `0508b3413137917e` | decoder + test synthétique |
| `SetSocialClaimAuthorityEvent` | `3c767f84ef34fe0e` | decoder + test synthétique |
### Discriminators Solscan hors IDL locale
Ces discriminators ont été trouvés par filtres Solscan, mais ne sont pas observés dans le corpus local final et ne sont pas dans l'IDL locale fournie. Ils restent conservés en coverage comme surfaces futures :
| Event | Discriminator | Statut |
|---|---:|---|
| `revoke_fee_sharing_authority_event` | `7217653c0ebe993e` | `upstream_git_mapped_unverified` |
| `transfer_fee_sharing_authority_event` | `7c8fc6f54db808ec` | `upstream_git_mapped_unverified` |
## Écarts observed/materialized
Les écarts `observed_count > materialized_count` sont expliqués par des transactions failed ou par une politique decoded-only. La requête `09b` documente notamment :
| Entrée | Observed | Materialized | Explication |
|---|---:|---:|---|
| `get_fees` | `5` | `0` | decoded-only volontaire |
| `claim_social_fee_pda_v2` | `25` | `21` | `4` failed decoded |
| `create_fee_sharing_config` | `36` | `33` | `3` failed decoded |
| `initialize_fee_config` | `5` | `2` | `3` failed decoded |
| `social_fee_pda_claimed` | `17` | `15` | `2` failed decoded |
| `crank_donation_fee_pda` | `14` | `12` | `2` failed decoded |
| `update_fee_shares_v2` | `19` | `17` | `2` failed decoded |
| `revoke_fee_sharing_authority` | `6` | `5` | `1` failed decoded |
La requête `06` confirme qu'il n'existe aucun successful non-materialized sans skip/policy explicite.
## Checks de fermeture
SQL dédié : `validation_sql/SQL_VALIDATION_PUMP_FEES_0_7_55.sql`.
Résultats de fermeture rapportés :
- fallback `upstream_git` `pump_fees` : vide ;
- `instruction_name` `pump_fees` vide : vide ;
- `event_family = unknown` ou vide pour instruction/event : vide ;
- decoded `pump_fees` sans coverage : vide ;
- fallback résiduel pour entrées couvertes localement : vide ;
- successful non-materialized sans skip/policy : vide ;
- failed transaction avec business materialization : vide ;
- multi-target materialization : vide ;
- anti-trade/candle direct `pump_fees` : vide ;
- watchlist globale : plus aucun `pump_fees`, reste seulement `jupiter_swap.route_v2` comme backlog ponctuel.
## Statut final
`0.7.55 pump_fees` est clôturé techniquement. Ne pas rouvrir `pump_fees`, `pump_fun`, `pump_swap` ou Raydium sans bug prouvé par SQL/code ou apparition d'un nouveau discriminant/corpus externe exploitable.

View File

@@ -0,0 +1,127 @@
<!-- file: docs/reports/PUMP_FUN_EVENT_COVERAGE_REPORT.md -->
# Pump.fun event coverage report — clôture `0.7.54`
## Statut du rapport
Ce rapport clôture la tranche `0.7.54 pump_fun` côté coverage, décodage local, matérialisation métier prudente et validation SQL.
Program id canonique :
```text
6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
```
Source IDL locale prioritaire :
```text
idls/pump_fun.6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P.json
```
## Sources utilisées
- `kb_lib/src/dex/pump_fun.rs` ;
- `kb_lib/src/dex_decode.rs` ;
- `kb_lib/src/trade_aggregation.rs` ;
- `kb_lib/src/trade_amount_resolution.rs` ;
- `kb_lib/src/dex_detection_route.rs` ;
- `kb_lib/src/dex_event_coverage.rs` ;
- `kb_lib/src/upstream_registry_generated.rs` ;
- `idls/pump_fun.6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P.json` ;
- `validation_sql/SQL_VALIDATION_PUMP_FUN_0_7_54.sql` ;
- `validation_sql/SQL_VALIDATION_PUMP_FUN_MATERIALIZATION_0_7_54.sql` ;
- corpus SQLite bâti par backfills Demo3/signatures/pools et replay forcé.
## Couverture finale
L'IDL locale Pump.fun contient `40` instructions et `23` events Anchor. La tranche a ajouté la couverture locale des instructions/events connues, y compris les instructions IDL-only absentes du registre upstream initial :
- `add_quote_mint` ;
- `buy_exact_quote_in_v2` ;
- `buy_v2` ;
- `claim_cashback_v2` ;
- `collect_creator_fee_v2` ;
- `distribute_creator_fees_v2` ;
- `migrate_v2` ;
- `remove_quote_mint` ;
- `sell_v2` ;
- `set_virtual_quote_reserves` ;
- `update_buyback_config`.
Les events Anchor sont reconnus depuis `Program data:` et depuis le transport Anchor self-CPI/log `e445a52e51cb9a1d` quand présent.
## Règles de matérialisation finales
### Trades
| Source locale | Matérialisation | Règle |
|---|---|---|
| `pump_fun.buy` | `k_sol_trade_events` | directe si montants fiables |
| `pump_fun.sell` | `k_sol_trade_events` | directe si montants fiables |
| `pump_fun.buy_exact_sol_in` | `k_sol_trade_events` | directe ; les logs `Program data` tronqués sont exploités quand les montants exacts sont extractibles |
| `pump_fun.buy_v2` | non directe | instruction audit/coverage/routing uniquement |
| `pump_fun.sell_v2` | non directe | instruction audit/coverage/routing uniquement |
| `pump_fun.buy_exact_quote_in_v2` | non directe | instruction audit/coverage/routing uniquement |
| `pump_fun.trade_event` | `k_sol_trade_events` | source canonique des montants exécutés v2/exact quand corrélée sans ambiguïté |
Les `trade_event` déjà couverts par une instruction directe reçoivent un skip explicite afin d'éviter tout double-count.
### Non-trades
Les événements non-trade sont matérialisés uniquement vers leur table métier ciblée quand les comptes, acteurs et montants sont fiables :
- `k_sol_launch_events` pour create/migrate/graduate ;
- `k_sol_fee_events` pour creator fees, fee distribution et minimum fee ;
- `k_sol_reward_events` pour cashback, incentives et volume accumulators exploitables ;
- `k_sol_pool_admin_events` pour admin/config/creator/global authority ;
- `k_sol_pool_lifecycle_events` pour initialization/lifecycle.
Sinon, ils restent decoded-only/audit-only avec `skip*Reason` explicite. Les transactions failed ne produisent aucune matérialisation métier.
## Replay final rapporté
```text
1679 replayed
0 decode skipped
1679 ledger upserts
145 unsafe ledger rows
89 trades
0 liquidity
10 lifecycle
0 tokenAccount
348 candle upserts
instructionObservations = 13905
resetDeleted = 1112
catalog = 52 tokens / 50 pools / 50 pairs
```
## Matérialisation finale Pump.fun observée
```text
pump_fun.buy 17 trades
pump_fun.sell 25 trades
pump_fun.buy_exact_sol_in 15 trades
pump_fun.trade_event 25 trades
```
Les variantes v2/exact restent à `0` dans `k_sol_trade_events` par `decoded_event_id` d'instruction, ce qui est attendu : leur matérialisation canonique se fait via `pump_fun.trade_event`.
## Checks de fermeture SQL
Résultats finaux rapportés :
- `Q00` upstream fallback Pump.fun : vide ;
- `Q04` decoded Pump.fun sans coverage : vide ;
- `Q05` fallback upstream couvert localement : vide ;
- `Q06` successful non-materialized sans skip reason : vide ;
- `Q07` failed transaction materialization safety : vide ;
- `Q08` multi-target materialization safety : vide ;
- `Q11` trade candidates sans trade ni skip : vide ;
- `Q12` watchlist globale : plus de `pump_fun` ; restent `pump_fees`, `jupiter_swap` et `dflow_aggregator_v4`.
## Décisions de clôture
- `pump_fun` est clos côté decoder maximal local et validation corpus.
- Les prochaines interventions Pump.fun doivent être des corrections de bugs ou des adaptations à un changement externe prouvé.
- La suite logique est `0.7.55 pump_fees` sur nouvelle base SQLite.
- La politique reste : tout ce qui peut être décodé doit l'être ; tout ce qui peut être matérialisé de manière fiable doit l'être ; aucun trade/candle artificiel ne doit être créé.

View File

@@ -0,0 +1,168 @@
<!-- file: docs/reports/PUMP_SWAP_EVENT_COVERAGE_REPORT.md -->
# PumpSwap event coverage report — `0.7.53`
## Scope
- Version cible : `0.7.53`.
- Surface unique : `pump_swap`.
- Program id unique : `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA`.
- Phasage : une version = un `program_id`.
- `raydium_pool_v4.json` reste repoussé vers la fin du phasage et ne bloque pas cette tranche.
## Sources vérifiées / à vérifier pendant la fermeture
- `kb_lib/src/constants.rs`, notamment `PUMP_SWAP_PROGRAM_ID` et `SOLSCAN_ACCOUNT_SOURCES`.
- Registre upstream local généré : `kb_lib/src/upstream_registry_generated.rs`.
- Sources Git/IDL externes disponibles : Pump public docs / IDL, Carbon, fnzero, Pinax, HODL Warden si présents dans le registre.
- IDL locale : `idls/pump_swap.pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA.json`, téléchargée depuis Solscan et versionnée dans le workspace.
- Solscan IDL du program id PumpSwap si disponible.
- Corpus local Demo3 + backfills signature/pool.
- `k_sol_dex_event_coverage_entries` après replay forcé.
Les sources Git/IDL/Solscan sont des indices. La fermeture métier exige corpus local, replay et SQL.
## Couverture locale ajoutée
Le decoder local `kb_lib/src/dex/pump_swap.rs` ne se limite plus à `buy`/`sell`. Il reconnaît maintenant les discriminants dinstruction suivants et produit un event spécialisé `pump_swap.<entry_name>`.
| Entry | Kind | Discriminator | Target attendu | Matérialisation |
|---|---|---:|---|---|
| `admin_set_coin_creator` | instruction | `f228759149606968` | admin/config | decoded specialized non-trade |
| `admin_update_token_incentives` | instruction | `d10b7357d5177ccc` | reward/admin | decoded specialized non-trade |
| `buy` | instruction | `66063d1201daebea` | trade | trade/candle seulement depuis montants exacts |
| `buy_exact_quote_in` | instruction | `c62e1552b4d9e870` | trade conditionnel | matérialisé seulement si un `BuyEvent` Anchor exact est présent (`amountSource=pump_swap_anchor_buy_event`) ; sinon decoded-only `instruction_bounds_only` avec `skipTradeReason` |
| `claim_cashback` | instruction | `253a237ebe35e4c5` | reward | decoded specialized non-trade |
| `claim_token_incentives` | instruction | `1004471ccc01281b` | reward | decoded specialized non-trade |
| `close_user_volume_accumulator` | instruction | `f945a4da9667548a` | reward | decoded specialized non-trade |
| `collect_coin_creator_fee` | instruction | `a039592ab58b2b42` | fee | decoded specialized non-trade |
| `create_config` | instruction | `c9cff3724b6f2fbd` | admin/config | decoded specialized non-trade |
| `create_pool` | instruction | `e992d18ecf6840bc` | pool lifecycle | decoded specialized non-trade |
| `deposit` | instruction | `f223c68952e1f2b6` | liquidity add | decoded specialized non-trade |
| `disable` | instruction | `b9adbb5ad80feee9` | admin/config | decoded specialized non-trade |
| `extend_account` | instruction | `ea66c2cb96483ee5` | admin/config | decoded specialized non-trade |
| `init_user_volume_accumulator` | instruction | `5e06ca73ff60e8b7` | reward | decoded specialized non-trade |
| `migrate_pool_coin_creator` | instruction | `d0089f044aaf103a` | admin/migration | decoded specialized non-trade |
| `sell` | instruction | `33e685a4017f83ad` | trade | trade/candle seulement depuis montants exacts |
| `set_coin_creator` | instruction | `d295802dbc3a4eaf` | admin/config | decoded specialized non-trade |
| `set_reserved_fee_recipients` | instruction | `6faca2e87259d58e` | admin/config | decoded specialized non-trade |
| `set_reserved_fee_recipient` | instruction | `cfbdb247a77a44b4` | admin/config | local log proof only: `Instruction: SetReservedFeeRecipient` ; absent from checked Solscan IDL raw ; decoded specialized non-trade |
| `sync_user_volume_accumulator` | instruction | `561fc057a3574fee` | reward | decoded specialized non-trade |
| `toggle_cashback_enabled` | instruction | `7367e0ffbd5956c3` | admin/config | decoded specialized non-trade |
| `toggle_mayhem_mode` | instruction | `01096fd0641fffa3` | admin/config | decoded specialized non-trade |
| `transfer_creator_fees_to_pump` | instruction | `8b348655e4e56cf1` | fee | decoded specialized non-trade |
| `transfer_creator_fees_to_pump_v2` | instruction | `01214eb921432c5c` | fee | Solscan IDL proof + local log proof: `transfer_creator_fees_to_pump_v2` / `Instruction: TransferCreatorFeesToPumpV2` ; decoded specialized non-trade |
| `update_admin` | instruction | `a1b028d53cb8b3e4` | admin/config | decoded specialized non-trade |
| `update_buyback_config` | instruction | `fbe0ab92a01a71e9` | admin/config | Solscan IDL proof + local log proof: `update_buyback_config` / `Instruction: UpdateBuybackConfig` ; decoded specialized non-trade |
| `update_fee_config` | instruction | `68b867f258976b14` | admin/config | decoded specialized non-trade |
| `withdraw` | instruction | `b712469c946da122` | liquidity remove | decoded specialized non-trade |
## Upstream Program-data events à statut explicite
Ces events sont listés dans le registre upstream. Ils doivent apparaître avec un statut explicite dans la coverage DB après sync/replay. Ils ne doivent pas créer de doublons trade/candle tant que linstruction locale spécialisée couvre déjà le DEX effectif.
| Event | Discriminator | Statut `0.7.53` |
|---|---:|---|
| `admin_set_coin_creator_event` | `2ddc5d181961ac68` | upstream listed ; decoded-only/status explicite après replay |
| `admin_update_token_incentives_event` | `93fa6c78f71d43de` | upstream listed ; decoded-only/status explicite après replay |
| `buy_event` | `67f4521f2cf57777` | upstream listed ; audit/decoded-only to avoid duplicate trade |
| `claim_cashback_event` | `e2d6f62107f293e5` | upstream listed ; decoded-only/status explicite après replay |
| `claim_token_incentives_event` | `4facf631cd5bcee8` | upstream listed ; decoded-only/status explicite après replay |
| `close_user_volume_accumulator_event` | `929fbdac925838f4` | upstream listed ; decoded-only/status explicite après replay |
| `collect_coin_creator_fee_event` | `e8f5c2eeeada3a59` | upstream listed ; decoded-only/status explicite après replay |
| `create_config_event` | `6b34598137e25116` | upstream listed ; decoded-only/status explicite après replay |
| `create_pool_event` | `b1310cd2a076a774` | upstream listed ; decoded-only/status explicite après replay |
| `deposit_event` | `78f83d531f8e6b90` | upstream listed ; decoded-only/status explicite après replay |
| `disable_event` | `6bfdc14ce4ca1b68` | upstream listed ; decoded-only/status explicite après replay |
| `extend_account_event` | `6161d7905d92167c` | upstream listed ; decoded-only/status explicite après replay |
| `init_user_volume_accumulator_event` | `86240d48e86582d8` | upstream listed ; decoded-only/status explicite après replay |
| `migrate_pool_coin_creator_event` | `aadd52c793a5f72e` | upstream listed ; decoded-only/status explicite après replay |
| `reserved_fee_recipients_event` | `2bbcfa12dd4bbb5f` | upstream listed ; decoded-only/status explicite après replay |
| `sell_event` | `3e2f370aa503dc2a` | upstream listed ; audit/decoded-only to avoid duplicate trade |
| `set_bonding_curve_coin_creator_event` | `f2e7eb664163bdd3` | upstream listed ; decoded-only/status explicite après replay |
| `set_metaplex_coin_creator_event` | `966bc77b7ccf66e4` | upstream listed ; decoded-only/status explicite après replay |
| `sync_user_volume_accumulator_event` | `c57aa77c74515bff` | upstream listed ; decoded-only/status explicite après replay |
| `update_admin_event` | `e198ab57f63f42ea` | upstream listed ; decoded-only/status explicite après replay |
| `update_fee_config_event` | `5a1741233ef4bcd0` | upstream listed ; decoded-only/status explicite après replay |
| `withdraw_event` | `1609851aa02c47c0` | upstream listed ; decoded-only/status explicite après replay |
## Matérialisation
- `pump_swap.buy`, `pump_swap.sell` et `pump_swap.buy_exact_quote_in` peuvent alimenter `k_sol_trade_events`, mais seulement depuis des montants exacts.
- `pump_swap.buy_exact_quote_in` est matérialisé quand le log Anchor `BuyEvent` fournit `baseAmountOutRaw` et `userQuoteAmountInRaw` pour `ixName=buy_exact_quote_in`. Les rows `instruction_bounds_only` restent decoded-only avec `skipTradeReason` explicite.
- Les bornes dinstruction (`maxQuoteAmountIn`, `spendableQuoteAmountIn`, `minQuoteAmountOut`, `minBaseAmountOut`) ne sont pas considérées comme des montants exacts suffisants pour créer un trade/candle.
- La matérialisation doit passer par les résolutions exactes existantes : token transfer deltas, vault/account balance deltas ou autre source damount explicitement prouvée.
- Les transactions failed restent decoded-only via lactionability `failed_transaction`.
- Les non-trades restent hors `k_sol_trade_events` et hors `k_sol_pair_candles`.
## SQL de fermeture
Le fichier dédié est :
```text
validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql
```
Les requêtes danomalies attendues vides couvrent :
- fallback upstream résiduel sur instruction couverte localement ;
- failed tx avec trade ;
- non-swap avec trade ;
- decoded without coverage ;
- successful non-materialized inexpliqué ;
- multi-target materialization ;
- successful swap exploitable sans trade et sans raison explicite.
## Delta post-replay `0.7.53-pump_swap-delta-1`
Le replay local a révélé trois écarts corrigés par ce delta :
- `pump_swap.toggle_cashback_enabled` était classé à la fois `reward` et `admin`; il devient admin-only pour respecter linvariant single-target.
- `pump_swap.buy_exact_quote_in` réussi non matérialisé reçoit maintenant un `skipTradeReason` explicite et reste decoded-only tant que les montants exacts ne sont pas prouvés.
- `k_sol_instruction_observations.instruction_name` reçoit un mapping PumpSwap par discriminant pour que la requête de coverage locale ne sorte plus des noms vides. Le discriminant `e445a52e51cb9a1d` reste marqué comme transport technique Anchor self-CPI. Les trois discriminants initialement inconnus ne doivent plus sortir en `observed_unknown_*` : deux sont confirmés par le raw Solscan IDL et un reste conservé comme local-log-only.
`pump_swap.migrate_pool_coin_creator` est également forcé en admin/config, pas lifecycle, car il modifie lattribution coin creator et ne représente pas une migration de pool échangeable.
## Delta post-replay `0.7.53-pump_swap-delta-2`
- Les trois discriminants initialement inconnus (`01214eb921432c5c`, `fbe0ab92a01a71e9`, `cfbdb247a77a44b4`) ont été provisoirement couverts decoded-only pour supprimer les gaps locaux sans inventer de métier.
- `toggle_cashback_enabled` est corrigé aussi dans la famille coverage (`admin_config`) afin de refléter la matérialisation admin-only.
## Delta post-replay `0.7.53-pump_swap-delta-4`
- Le corpus local donne maintenant le nom métier via logs Anchor : `TransferCreatorFeesToPumpV2`, `UpdateBuybackConfig`, `SetReservedFeeRecipient`.
- Ces trois discriminants deviennent des instructions locales spécialisées : `pump_swap.transfer_creator_fees_to_pump_v2`, `pump_swap.update_buyback_config`, `pump_swap.set_reserved_fee_recipient`.
- Recomparaison raw Solscan IDL : `transfer_creator_fees_to_pump_v2` et `update_buyback_config` sont présents dans lIDL. `set_reserved_fee_recipient` nest pas listé dans ce raw ; il est gardé sur preuve log locale, possiblement instruction historique/supprimée ou non exposée par cette version IDL.
- `transfer_creator_fees_to_pump_v2` est fee/non-trade ; `update_buyback_config` et `set_reserved_fee_recipient` sont admin/config non-trade.
## Clôture finale `0.7.53`
La tranche est clôturée après les deltas de consolidation :
- `buy_exact_quote_in` route désormais vers la matérialisation pool/pair/trade quand `amountSource=pump_swap_anchor_buy_event`;
- les montants du `BuyEvent` sont normalisés par rapport à lordre local de la paire pour éviter les inversions base/quote ;
- les events Anchor PumpSwap sont décodés comme events autonomes audit-only ;
- `claim_token_incentives_event` possède un test synthétique de matérialisabilité reward si un corpus réussi apparaît ;
- `sync_user_volume_accumulator_event` reste implémenté mais non observé malgré un backfill élargi sur linstruction ;
- les tests synthétiques couvrent les instructions/events IDL non observés localement ;
- `cargo test -p kb_lib` a été validé à `421 passed / 0 failed` et clippy est OK côté utilisateur.
Résultats de validation rapportés après corpus élargi :
```text
pump_swap decoded without coverage = vide
pump_swap upstream fallback couvert localement = vide
successful trade candidates sans trade = vide
failed tx avec business trade = vide
non-swap matérialisé en trade = vide
multi-target materialization = vide
buy_exact_quote_in / pump_swap_anchor_buy_event = 168 decoded / 167 trades / 1 failed tx
```
Les fichiers de surveillance à conserver sont :
- `validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql` ;
- `validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql` ;
- `docs/reports/DEX_COVERAGE_GLOBAL_WATCHLIST_0_7_53.md`.

View File

@@ -0,0 +1,141 @@
<!-- file: docs/reports/RAYDIUM_AMM_V4_EVENT_COVERAGE_REPORT.md -->
# Raydium AMM v4 Event Coverage Report — `0.7.51-final`
## Scope
Tranche : `0.7.51 raydium_amm_v4`.
Program id canonique local :
```text
675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
```
Code local canonique :
```text
raydium_amm_v4
```
Cette tranche reprend AMM v4 legacy après `0.7.50 raydium_launchpad` et les rechecks CPMM/CLMM. Les sources Git/IDL/Solscan restent des indices ; les statuts observé/matérialisé proviennent du corpus local et du replay forcé.
## Sources inventoriées
Sources utilisées comme indices de coverage :
- Carbon : `decoders/raydium-amm-v4-decoder` ;
- Pinax : `src/raydium/amm` ;
- fnzero `sol-parser-sdk` : `idl/raydium_amm_v4.json` et `idls/raydium_amm_v4.json` ;
- fnzero `sol-parser-sdk` : `idl/raydium_pool_v4.json` et `idls/raydium_pool_v4.json`, audit comparatif uniquement ;
- Solscan Program IDL et recherche `instruction=<discriminator>` pour `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`.
## Validation Rust et replay final
Validation locale rapportée :
```text
cargo test -p kb_lib -> 405 passed / 0 failed
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
```
Replay local final :
```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
```
## Coverage finale par discriminant
| Discriminant | Entrée | Famille | Local event kind | Cible DB | Observed | Materialized | Trade |
|---|---|---|---|---|---:|---:|---:|
| `00` | `initialize` | `pool_create` | `raydium_amm_v4.initialize` | `k_sol_pool_lifecycle_events` | 4 | 4 | 0 |
| `01` | `initialize2` | `pool_create` | `raydium_amm_v4.initialize2_pool` | `k_sol_pool_lifecycle_events` | 8 | 8 | 0 |
| `02` | `monitor_step` | `order_place` | `raydium_amm_v4.monitor_step` | `k_sol_orderbook_events` | 20 | 20 | 0 |
| `03` | `deposit` | `liquidity_add` | `raydium_amm_v4.deposit` | `k_sol_liquidity_events` | 10 | 5 | 0 |
| `04` | `withdraw` | `liquidity_remove` | `raydium_amm_v4.withdraw` | `k_sol_liquidity_events` | 3 | 2 | 0 |
| `05` | `migrate_to_open_book` | `order_place` | `raydium_amm_v4.migrate_to_open_book` | `k_sol_orderbook_events` | 6 | 6 | 0 |
| `06` | `set_params` | `admin_config` | `raydium_amm_v4.set_params` | `k_sol_pool_admin_events` | 1 | 1 | 0 |
| `07` | `withdraw_pnl` | `fee` | `raydium_amm_v4.withdraw_pnl` | `k_sol_fee_events` | 1 | 1 | 0 |
| `08` | `withdraw_srm` | `fee` | `raydium_amm_v4.withdraw_srm` | `k_sol_fee_events` | 2 | 1 | 0 |
| `09` | `swap_base_in` | `swap` | `raydium_amm_v4.swap_base_in` | `k_sol_trade_events` | 76 | 66 | 66 |
| `0a` | `pre_initialize` | `pool_create` | `raydium_amm_v4.pre_initialize` | `k_sol_pool_lifecycle_events` | 8 | 7 | 0 |
| `0b` | `swap_base_out` | `swap` | `raydium_amm_v4.swap_base_out` | `k_sol_trade_events` | 3 | 1 | 1 |
| `0c` | `simulate_info` | `cpi_transport` | `raydium_amm_v4.simulate_info` | `k_sol_dex_decoded_events_only` | 6 | 0 | 0 |
| `0d` | `admin_cancel_orders` | `order_cancel` | `raydium_amm_v4.admin_cancel_orders` | `k_sol_orderbook_events` | 22 | 22 | 0 |
| `0e` | `create_config_account` | `admin_config` | `raydium_amm_v4.create_config_account` | `k_sol_pool_admin_events` | 50 | 50 | 0 |
| `0f` | `update_config_account` | `admin_config` | `raydium_amm_v4.update_config_account` | `k_sol_pool_admin_events` | 6 | 6 | 0 |
| `10` | `swap_base_in_v2` | `swap` | `raydium_amm_v4.swap_base_in_v2` | `k_sol_trade_events` | 35 | 35 | 35 |
| `11` | `swap_base_out_v2` | `swap` | `raydium_amm_v4.swap_base_out_v2` | `k_sol_trade_events` | 7 | 7 | 7 |
Toutes les entrées ont `proof_status=upstream_git_local_corpus_materialized`, sauf `simulate_info`, qui reste volontairement `upstream_git_local_corpus_observed` / decoded-only.
## Matérialisation métier finale
| Event kind | Decoded | Trade | Liquidity | Lifecycle | Fee | Admin | Orderbook |
|---|---:|---:|---:|---:|---:|---:|---:|
| `raydium_amm_v4.admin_cancel_orders` | 22 | 0 | 0 | 0 | 0 | 0 | 22 |
| `raydium_amm_v4.create_config_account` | 50 | 0 | 0 | 0 | 0 | 50 | 0 |
| `raydium_amm_v4.deposit` | 10 | 0 | 5 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.initialize2_pool` | 8 | 0 | 0 | 8 | 0 | 0 | 0 |
| `raydium_amm_v4.migrate_to_open_book` | 6 | 0 | 0 | 0 | 0 | 0 | 6 |
| `raydium_amm_v4.monitor_step` | 20 | 0 | 0 | 0 | 0 | 0 | 20 |
| `raydium_amm_v4.pre_initialize` | 8 | 0 | 0 | 7 | 0 | 0 | 0 |
| `raydium_amm_v4.set_params` | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
| `raydium_amm_v4.simulate_info` | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.swap_base_in` | 76 | 66 | 0 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.swap_base_in_v2` | 35 | 35 | 0 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.swap_base_out` | 3 | 1 | 0 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.swap_base_out_v2` | 7 | 7 | 0 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.update_config_account` | 6 | 0 | 0 | 0 | 0 | 6 | 0 |
| `raydium_amm_v4.withdraw` | 3 | 0 | 2 | 0 | 0 | 0 | 0 |
| `raydium_amm_v4.withdraw_pnl` | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
| `raydium_amm_v4.withdraw_srm` | 2 | 0 | 0 | 0 | 1 | 0 | 0 |
## Invariants validés
Les requêtes finales donnent `vide` pour :
- `raydium_amm_v4.swap` legacy ;
- decoded AMM v4 sans coverage entry ;
- observations AMM v4 dont `length(discriminator_hex) > 2` ;
- non-swap AMM v4 avec trade ;
- transaction failed AMM v4 avec trade ;
- event successful non matérialisé sans raison explicite ;
- event AMM v4 matérialisé vers plus d'une table métier principale.
## Gaps expliqués
Les écarts `observed_count > materialized_count` sont acceptés uniquement s'ils sont expliqués :
- `swap_base_in` / `swap_base_out` : decoded-only lorsque les deltas vault ou montants exploitables sont absents ;
- `deposit` / `withdraw` : non matérialisés lorsque le pool/pair catalogue ou les deltas nécessaires sont absents ;
- `withdraw_srm` : non matérialisé si le contexte fee exploitable est absent ;
- `pre_initialize` : 1 transaction failed ; les 7 transactions successful sont matérialisées en lifecycle audit minimal ;
- `simulate_info` : decoded-only assumé.
Pour `deposit`, le corpus final montre 5 événements matérialisés sur le pool catalogué `2dRNngAm729NzLbb1pzgHtfHvPqR4XHFmFyYK78EfEeX` / pair `FIDA/RAY`, et 5 événements decoded-only sur des pools absents du catalogue local.
## Décisions spécifiques
- `raydium_amm_v4.swap` est définitivement interdit : les swaps doivent rester spécialisés.
- `pre_initialize` est conservé pour les scans historiques, matérialisé comme lifecycle audit deprecated/partial, sans pair exploitable.
- `migrate_to_open_book`, `monitor_step` et `admin_cancel_orders` sont des side effects orderbook AMM v4, pas des trades OpenBook autonomes.
- `simulate_info` reste `k_sol_dex_decoded_events_only`.
- Les side effects SPL Token / Token-2022 restent transversaux.
- `raydium_pool_v4` n'est pas promu en decoder autonome dans `0.7.51`.
## Clôture
`0.7.51 raydium_amm_v4` est clôturable côté `kb_lib` sous réserve de conserver les rechecks CPMM/CLMM/Launchpad dans la validation globale de workspace lorsque la base utilisée les contient.

View File

@@ -0,0 +1,140 @@
<!-- file: docs/reports/RAYDIUM_CLMM_EVENT_COVERAGE_REPORT.md -->
# Rapport `0.7.49` — Raydium CLMM event coverage
## Résumé
La tranche `0.7.49` clôture la couverture fonctionnelle `raydium_clmm` sur le corpus local validé. Elle reprend CLMM après `0.7.48 raydium_cpmm` et applique la même méthode : inventaire upstream, corpus local, replay forcé, materialization contrôlée, suppression des fallbacks remplacés, validation SQL.
Validation locale observée après le dernier replay :
```text
local replay: 2197 replayed, 0 decode skipped, 2197 ledger upserts, 1461 unsafe ledger rows, 1217 trades, 111 liquidity, 25 lifecycle, 4868 candle upserts, instructionObservations=19798
catalog: 41 tokens, 63 pools, 63 pairs
```
Synthèse coverage :
```text
listed_entry_count = 45
decoded_entry_count = 33
observed_entry_count = 33
materialized_entry_count = 25
total_observed_count = 2560
total_materialized_count = 1367
trade_count = 1186
```
## Entrées couvertes
La tranche couvre `33` instructions locales CLMM observées et décodées, dont :
```text
swap
swap_v2
swap_router_base_in
open_position
open_position_v2
open_position_with_token22_nft
close_position
close_protocol_position
increase_liquidity
increase_liquidity_v2
decrease_liquidity
decrease_liquidity_v2
create_pool
create_customizable_pool
create_amm_config
create_dynamic_fee_config
update_amm_config
update_pool_status
create_operation_account
update_operation_account
create_support_mint_associated
collect_fund_fee
collect_protocol_fee
collect_remaining_rewards
initialize_reward
set_reward_params
transfer_reward_owner
update_reward_infos
open_limit_order
increase_limit_order
decrease_limit_order
close_limit_order
settle_limit_order
```
## Matérialisations validées
Les matérialisations sont limitées aux transactions réussies et aux familles déjà supportées par le modèle DB :
| Famille | Table | Règle |
|---|---|---|
| Swaps | `k_sol_trade_events` + candles | Uniquement `raydium_clmm.swap` / `raydium_clmm.swap_v2` quand les montants sont exploitables. |
| Liquidity / positions | `k_sol_liquidity_events` | Positions/liquidity prouvées par corpus, sans trade/candle. |
| Fees | `k_sol_fee_events` | Fees prouvées par corpus, sans trade/candle. |
| Rewards | `k_sol_reward_events` | Rewards prouvées par corpus, sans trade/candle. |
| Admin/config | `k_sol_pool_admin_events` | Config/admin prouvés par corpus, sans trade/candle. |
| Lifecycle | `k_sol_pool_lifecycle_events` | Pool creation prouvée par corpus, sans trade/candle. |
| Limit orders | `k_sol_orderbook_events` | Open/increase/decrease/close/settle matérialisés comme orderbook, jamais trade/candle. |
## Invariants validés
Les requêtes SQL finales valident :
```text
raydium_clmm.instruction_audit résiduel = 0
upstream_git.instruction_match localement couvert = 0
non-swap CLMM avec trade_count > 0 = 0
failed tx matérialisées = 0
```
Les fallbacks `upstream_git.instruction_match` localement couverts sont supprimés automatiquement, y compris quand `k_sol_instruction_observations.decoded_event_id` pointait encore vers une ligne fallback.
## Anchor / Program-data events non observés
Les `11` Anchor / `Program data` events CLMM ci-dessous restent listés en `upstream_git_unverified`, car aucun corpus local ne les observe encore comme event direct :
```text
collect_personal_fee_event a6ae69c051a15369
collect_protocol_fee_event ce57114f2d29d53d
config_change_event f7bd07776a705f97
create_personal_position_event 641e57f9c4df9ace
decrease_liquidity_event 3ade563a44325538
increase_liquidity_event 314f69d420221e54
liquidity_calculate_event ed7094e63954b4a2
liquidity_change_event 7ef0afce9e58996b
pool_created_event 195e4b2f7063353f
swap_event 40c6cde8260871e2
update_reward_infos_event 6d7fba4e724125ec
```
Le code est préparé pour les accueillir comme audit-only lorsquils seront observés dans un corpus local. Ils ne produisent pas de trade/candle par défaut.
## Sources utilisées
Les entrées ont été comparées aux sources Raydium CLMM suivantes :
```text
Solscan Program IDL CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK
sevenlabs-hq/carbon raydium-clmm-decoder
pinax-network/substreams-solana-idls raydium/clmm
0xfnzero/sol-parser-sdk idl
```
Les sources upstream restent des indices. La promotion locale dépend du corpus local, du replay et des validations SQL.
## SQL final
La validation finale est dans :
```text
validation_sql/SQL_VALIDATION_RAYDIUM_CLMM_0_7_49.sql
```
## Addendum `0.7.50-pre-r2` — source parity CLMM
La re-vérification CLMM ajoute `cpi_event` (`e445a52e51cb9a1d`) et `update_dynamic_fee_config` (`0707500802c784f0`) depuis Carbon. Les Program-data events CLMM reçoivent maintenant un `local_event_kind` et une famille explicite quand ils sont observables localement : `swap_event`, `pool_created_event`, `liquidity_change_event`, `create_personal_position_event`, `decrease_liquidity_event`, `increase_liquidity_event`, `collect_protocol_fee_event`, `config_change_event` et `update_reward_infos_event`.
`create_support_mint_associated` est matérialisable dans la nouvelle table `k_sol_token_account_events`. `liquidity_calculate_event` reste decoded-only car il représente un calcul/diagnostic et non une mutation de liquidité fiable. `swap_event` et `swap_router_base_in` restent également decoded-only : les trades matérialisés proviennent des instructions `swap` et `swap_v2`, ce qui évite les doublons de Program-data events et les routes sans pool direct.

View File

@@ -0,0 +1,130 @@
<!-- file: docs/reports/RAYDIUM_CLMM_UPSTREAM_COVERAGE_REVIEW_PRE19.md -->
# Raydium CLMM upstream coverage review — `0.7.49-pre.19`
## Scope
Decoder under review:
```text
raydium_clmm
program_id = CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK
```
External sources checked for the local coverage registry:
```text
https://solscan.io/account/CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK#programIdl
https://github.com/sevenlabs-hq/carbon/tree/main/decoders/raydium-clmm-decoder
https://github.com/pinax-network/substreams-solana-idls/tree/main/src/raydium/clmm
https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl
```
Notes:
- Solscan is used as discovery / IDL cross-check, not as final business proof.
- `sol-parser-sdk/idl/raydium_clmm.json` maps to `raydium/amm_v3_with_swapv2.json` and exposes the CLMM program address.
- `pinax-network/substreams-solana-idls` exposes Raydium CLMM under `src/raydium/clmm/v3`.
- `sevenlabs-hq/carbon` exposes a dedicated `raydium-clmm-decoder` crate.
## Local registry status
The local registry now lists:
```text
45 entries total:
- 33 instructions
- 11 Anchor/program-data events
- 1 program row
```
All 33 instruction entries have a `local_event_kind` mapping in `dex_event_coverage.rs`, `instruction_observation_index.rs`, `dex_decode.rs`, and `upstream_registry_generated.rs`.
The 11 event entries are listed as upstream facts and stay `upstream_git_unverified` until local corpus provides program-data/Anchor event proof.
## Instruction coverage matrix
| Entry | Discriminator | Family | Local event kind | Expected target | Status |
|---|---|---|---|---|---|
| close_limit_order | `4c7c800fd55725fa` | order_cancel | `raydium_clmm.close_limit_order` | `k_sol_orderbook_events` | decoded/materializable |
| open_limit_order | `9d20dab7471d1293` | order_place | `raydium_clmm.open_limit_order` | `k_sol_orderbook_events` | decoded/materializable |
| increase_limit_order | `b19059ecfaba7d63` | order_place | `raydium_clmm.increase_limit_order` | `k_sol_orderbook_events` | decoded/materializable |
| decrease_limit_order | `759d3c674231a300` | order_cancel | `raydium_clmm.decrease_limit_order` | `k_sol_orderbook_events` | decoded/materializable |
| close_position | `7b86510031446262` | position_close | `raydium_clmm.close_position` | `k_sol_liquidity_events` | decoded/materializable |
| close_protocol_position | `c975989055556cb2` | position_close | `raydium_clmm.close_protocol_position` | `k_sol_liquidity_events` | decoded/materializable |
| collect_fund_fee | `a78a4e95dfc2067e` | fee | `raydium_clmm.collect_fund_fee` | `k_sol_fee_events` | decoded/materializable |
| collect_protocol_fee | `8888fcddc2427e59` | fee | `raydium_clmm.collect_protocol_fee` | `k_sol_fee_events` | decoded/materializable |
| collect_remaining_rewards | `12eda6c52210d590` | reward | `raydium_clmm.collect_remaining_rewards` | `k_sol_reward_events` | decoded/materializable |
| create_amm_config | `8934edd4d7756c68` | admin_config | `raydium_clmm.create_amm_config` | `k_sol_pool_admin_events` | decoded/materializable |
| create_customizable_pool | `2b44d4a7592fa401` | pool_create | `raydium_clmm.create_customizable_pool` | `k_sol_pool_lifecycle_events` | decoded/materializable |
| create_dynamic_fee_config | `bd0eb5785576e33e` | admin_config | `raydium_clmm.create_dynamic_fee_config` | `k_sol_pool_admin_events` | decoded/materializable |
| create_operation_account | `3f5794216d230868` | unknown | `raydium_clmm.create_operation_account` | `k_sol_dex_decoded_events_only` | decoded/audit-only unless admin evidence is required |
| create_pool | `e992d18ecf6840bc` | pool_create | `raydium_clmm.create_pool` | `k_sol_pool_lifecycle_events` | decoded/materializable |
| create_support_mint_associated | `11fb415c88f20ea9` | account_create | `raydium_clmm.create_support_mint_associated` | `k_sol_token_account_events` | decoded; token-account materialization remains a later cross-DEX topic |
| decrease_liquidity | `a026d06f685b2c01` | liquidity_remove | `raydium_clmm.decrease_liquidity` | `k_sol_liquidity_events` | decoded/materializable |
| decrease_liquidity_v2 | `3a7fbc3e4f52c460` | liquidity_remove | `raydium_clmm.decrease_liquidity_v2` | `k_sol_liquidity_events` | decoded/materializable |
| increase_liquidity | `2e9cf3760dcdfbb2` | liquidity_add | `raydium_clmm.increase_liquidity` | `k_sol_liquidity_events` | decoded/materializable |
| increase_liquidity_v2 | `851d59df45eeb00a` | liquidity_add | `raydium_clmm.increase_liquidity_v2` | `k_sol_liquidity_events` | decoded/materializable |
| initialize_reward | `5f87c0c4f281e644` | reward | `raydium_clmm.initialize_reward` | `k_sol_reward_events` | decoded/materializable |
| open_position | `87802f4d0f98f031` | position_open | `raydium_clmm.open_position` | `k_sol_liquidity_events` | decoded/materializable |
| open_position_v2 | `4db84ad67056f1c7` | position_open | `raydium_clmm.open_position_v2` | `k_sol_liquidity_events` | decoded/materializable |
| open_position_with_token22_nft | `4dffae527d1dc92e` | position_open | `raydium_clmm.open_position_with_token22_nft` | `k_sol_liquidity_events` | decoded/materializable |
| set_reward_params | `7034a74b20c9d389` | reward | `raydium_clmm.set_reward_params` | `k_sol_reward_events` | decoded/materializable |
| settle_limit_order | `cd4e74215c691a60` | settle_funds | `raydium_clmm.settle_limit_order` | `k_sol_orderbook_events` | decoded/materializable |
| swap | `f8c69e91e17587c8` | swap | `raydium_clmm.swap` | `k_sol_trade_events` | decoded/materializable as trade |
| swap_router_base_in | `457d73daf5baf2c4` | swap | `raydium_clmm.swap_router_base_in` | `k_sol_trade_events` | decoded; observed but not promoted to trade without corpus proof |
| swap_v2 | `2b04ed0b1ac91e62` | swap | `raydium_clmm.swap_v2` | `k_sol_trade_events` | decoded/materializable as trade |
| transfer_reward_owner | `07160c53f22b3079` | reward | `raydium_clmm.transfer_reward_owner` | `k_sol_reward_events` | decoded/materializable |
| update_amm_config | `313cae889a1c74c8` | admin_config | `raydium_clmm.update_amm_config` | `k_sol_pool_admin_events` | decoded/materializable |
| update_operation_account | `7f467728bce33d07` | unknown | `raydium_clmm.update_operation_account` | `k_sol_dex_decoded_events_only` | decoded/audit-only unless admin evidence is required |
| update_pool_status | `82576c062ee0757b` | admin_config | `raydium_clmm.update_pool_status` | `k_sol_pool_admin_events` | decoded/materializable |
| update_reward_infos | `a3ace0340b9a6adf` | reward | `raydium_clmm.update_reward_infos` | `k_sol_reward_events` | decoded/materializable |
## Anchor/program-data event entries
These entries remain listed, but no local corpus row has observed them as direct CLMM decoded events in the current replay corpus:
| Event entry | Discriminator | Family | Expected target | Status |
|---|---|---|---|---|
| collect_personal_fee_event | `a6ae69c051a15369` | fee | `k_sol_fee_events` | upstream listed, local corpus unobserved |
| collect_protocol_fee_event | `ce57114f2d29d53d` | fee | `k_sol_fee_events` | upstream listed, local corpus unobserved |
| config_change_event | `f7bd07776a705f97` | admin_config | `k_sol_pool_admin_events` | upstream listed, local corpus unobserved |
| create_personal_position_event | `641e57f9c4df9ace` | unknown | `k_sol_dex_decoded_events_only` | upstream listed, local corpus unobserved |
| decrease_liquidity_event | `3ade563a44325538` | liquidity_remove | `k_sol_liquidity_events` | upstream listed, local corpus unobserved |
| increase_liquidity_event | `314f69d420221e54` | liquidity_add | `k_sol_liquidity_events` | upstream listed, local corpus unobserved |
| liquidity_calculate_event | `ed7094e63954b4a2` | unknown | `k_sol_dex_decoded_events_only` | upstream listed, local corpus unobserved |
| liquidity_change_event | `7ef0afce9e58996b` | unknown | `k_sol_dex_decoded_events_only` | upstream listed, local corpus unobserved |
| pool_created_event | `195e4b2f7063353f` | unknown | `k_sol_dex_decoded_events_only` | upstream listed, local corpus unobserved |
| swap_event | `40c6cde8260871e2` | swap | `k_sol_trade_events` | upstream listed, local corpus unobserved |
| update_reward_infos_event | `6d7fba4e724125ec` | reward | `k_sol_reward_events` | upstream listed, local corpus unobserved |
## Patch `pre.19`
Patch goal:
```text
Stop replay/backfill from leaving `upstream_git.instruction_match` rows when a local specialized decoder already covers the same upstream decoder + entry + discriminator.
```
New DB query:
```text
query_dex_decoded_events_delete_locally_covered_upstream_instruction_matches(database, upstream_decoder_code)
```
Called from:
```text
local_pipeline_replay.rs::refresh_event_coverage_best_effort
token_backfill.rs::refresh_event_coverage_best_effort
```
Expected validation after replay:
```text
raydium_clmm.instruction_audit residual query -> empty
upstream_git.instruction_match where upstreamDecoderCode = raydium_clmm -> empty
non-swap CLMM trade_count -> empty
failed CLMM materialization query -> empty
coverage summary remains populated around 45 listed / 33 decoded / 33 observed
```

View File

@@ -0,0 +1,84 @@
<!-- file: docs/reports/RAYDIUM_CPMM_CLMM_RECHECK_REPORT_0_7_50_PRE_R2.md -->
# Raydium CPMM/CLMM re-check report — `0.7.50-pre-r2`
## Scope
This report closes the post-Launchpad re-check for `raydium_cpmm` and `raydium_clmm` using the same discipline applied to `raydium_launchpad`:
- every observed discriminator must have a named local event kind or an explicit decoded-only decision;
- `event_family='unknown'` is not acceptable outside synthetic `program` rows;
- materializable events must target the matching business table;
- duplicate, transport-only or context-incomplete events remain `k_sol_dex_decoded_events_only` by design;
- failed transactions must not produce business materialization.
## Sources
The source comparison for this tranche is based on:
- Carbon `raydium-cpmm-decoder`;
- Carbon `raydium-clmm-decoder`;
- Pinax `substreams-solana-idls` Raydium CPMM/CLMM trees;
- Solscan Program IDL pages for CPMM and CLMM;
- `0xfnzero/sol-parser-sdk` Raydium IDL snapshots;
- local corpus replay results from the dedicated CPMM and CLMM databases.
## CPMM decision
`40f4bc78a7e9690a` is now coded as:
```text
local_event_kind = raydium_cpmm.anchor_idl_instruction
event_family = idl_management
expected_db_target = k_sol_dex_decoded_events_only
```
Manual inspection of the three local signatures showed Anchor IDL management logs:
- `IdlCreateAccount` on `Hi6MkRTkcgwBi1WpiiudGPHKLuaKXKamNgVsy6YqoQeMRnrkpGjNx75ymrY59tJ3NN1GCn6nrndz9thMmwALLcY`;
- `IdlCloseAccount` on `Kch9bYneKzyPg13txxpu151QHX4EgQhFqXUHxqYLXE3BbSrMt56bNMx9JbMAZzs4fbuCLLibHAtrRHdrn7u2VUD`;
- `IdlCreateAccount` on `fsKqwEAiRCQyXvCBjBX4XGzkZXyz4DeNL1Kdw9BeyGYYAcTKPEP9sP4WXVNB2FRkvBXc3YjuGhUcihLZm3Y7Znu`.
This is not a CPMM business instruction. It must not produce trade, candle, liquidity, fee, admin or lifecycle rows.
## CPMM expected post-replay invariants
After replay on the CPMM database:
- observed discriminator coverage gap should be empty;
- residual `raydium_cpmm.instruction_audit` should be empty;
- decoded event kinds without coverage should be empty;
- materialization shortfall should be empty after excluding `k_sol_dex_decoded_events_only` and failed transactions;
- `swap_event` remains decoded-only because canonical trades come from `swap_base_input` / `swap_base_output`.
## CLMM decision
CLMM has no remaining unknown family in the coverage matrix. The re-check keeps the following entries decoded-only by design:
- `raydium_clmm.swap_event`: Program-data corroboration of swaps; canonical trade materialization remains on `swap` / `swap_v2`.
- `raydium_clmm.swap_router_base_in`: router instruction; no single direct pool surface should be inferred without hop-level resolution.
- `raydium_clmm.liquidity_calculate_event`: calculation/diagnostic event.
- `raydium_clmm.close_position` and `raydium_clmm.close_protocol_position`: decoded, but not materialized unless a reliable pool/pair context is available.
- `raydium_clmm.cpi_event`: Anchor transport only.
Materialization was strengthened for CLMM liquidity events by accepting snake_case amount keys (`amount0_raw`, `amount1_raw`, `liquidity_raw`) and by resolving pool/pair context from sibling decoded events in the same transaction when the current decoded event carries useful amounts but lacks direct pair context.
## CLMM expected post-replay invariants
After replay on the CLMM database:
- observed discriminator coverage gap should be empty;
- residual `raydium_clmm.instruction_audit` should be empty;
- decoded event kinds without coverage should be empty;
- failed transactions should not produce business rows;
- the validation SQL must count `k_sol_token_account_events`, otherwise `create_support_mint_associated` is falsely reported as a materialization gap.
## Validation files
Use:
```text
validation_sql/SQL_VALIDATION_RAYDIUM_CPMM_0_7_50_PRE_R2.sql
validation_sql/SQL_VALIDATION_RAYDIUM_CLMM_0_7_50_PRE_R2.sql
validation_sql/SQL_TRACE_RAYDIUM_CPMM_AUDIT_40F_0_7_50_PRE_R2.sql
```

View File

@@ -0,0 +1,214 @@
<!-- file: docs/reports/RAYDIUM_CPMM_EVENT_COVERAGE_REPORT.md -->
# Rapport `0.7.48` — Raydium CPMM event coverage
## Scope
Tranche : `0.7.48`.
Decoder local : `raydium_cpmm`.
Programme : `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C`.
Objectif : couvrir Raydium CPMM au-delà des swaps, avec preuve locale par backfill/replay SQL, sans modifier les règles trade/candle existantes et sans promouvoir de table métier transversale non nécessaire.
## Sources utilisées
Sources principales :
- Carbon `carbon-raydium-cpmm-decoder` ;
- fnzero `solana-streamer` / `sol-parser-sdk` IDL `raydium_cpmm.json` ;
- Raydium CP-Swap officiel ;
- Solscan page programme / Program IDL comme accélérateur de recherche de signatures, notamment via `instruction=<discriminator>`.
Règle retenue : Git/IDL/Solscan sont des indices de recherche. La preuve métier reste le corpus local backfillé puis rejoué.
## Entrées CPMM inventoriées
| Kind | Entrée | Discriminant | État final `0.7.48` |
|---|---|---|---|
| instruction | `close_permission_pda` | `9c5420764587467b` | connu upstream, non observé localement |
| instruction | `collect_creator_fee` | `1416567bc61cdb84` | décodé + matérialisé fee |
| instruction | `collect_fund_fee` | `a78a4e95dfc2067e` | décodé + matérialisé fee |
| instruction | `collect_protocol_fee` | `8888fcddc2427e59` | décodé + matérialisé fee |
| instruction | `create_amm_config` | `8934edd4d7756c68` | décodé + matérialisé admin/config |
| instruction | `create_permission_pda` | `878802d889a9b5ca` | décodé + matérialisé admin/config |
| instruction | `deposit` | `f223c68952e1f2b6` | décodé + matérialisé liquidity add |
| instruction | `initialize` | `afaf6d1f0d989bed` | décodé + matérialisé lifecycle |
| instruction | `initialize_with_permission` | `3f37fe4131b25979` | décodé + matérialisé lifecycle only |
| event | `lp_change_event` | `79a3cdc939da753c` | décodé + matérialisé liquidity bidirectionnelle |
| instruction | `swap_base_input` | `8fbe5adac41e33de` | décodé + trade matérialisé quand transaction OK |
| instruction | `swap_base_output` | `37d96256a34ab4ad` | décodé + trade matérialisé quand transaction OK |
| event | `swap_event` | `40c6cde8260871e2` | décodé audit-only, pas trade/candle |
| instruction | `update_amm_config` | `313cae889a1c74c8` | décodé + matérialisé admin/config |
| instruction | `update_pool_status` | `82576c062ee0757b` | connu upstream, non observé localement |
| instruction | `withdraw` | `b712469c946da122` | décodé + matérialisé liquidity remove |
## Décodage ajouté ou stabilisé
Le decoder spécialisé `raydium_cpmm` couvre maintenant :
- les swaps instruction-scoped `swap_base_input` / `swap_base_output` ;
- les events `Program data:` / Anchor CPI `swap_event` et `lp_change_event` ;
- les instructions lifecycle `initialize` / `initialize_with_permission` ;
- les instructions liquidity `deposit` / `withdraw` ;
- les fees `collect_creator_fee`, `collect_fund_fee`, `collect_protocol_fee` ;
- les instructions admin/config `create_amm_config`, `create_permission_pda`, `update_amm_config` ;
- les instructions connues mais non observées `close_permission_pda`, `update_pool_status` restent listées sans promotion métier.
Le fallback `upstream_git.instruction_match` ne doit plus apparaître pour les instructions CPMM couvertes localement.
## Matérialisation finale validée
Rejeu local validé après backfills ciblés Solscan + Demo Pipeline 2 :
| Event kind | Decoded | Table métier | Materialized | Trade count | Statut |
|---|---:|---|---:|---:|---|
| `raydium_cpmm.collect_creator_fee` | 4 | `k_sol_fee_events` | 4 | 0 | fee materialized |
| `raydium_cpmm.collect_fund_fee` | 7 | `k_sol_fee_events` | 7 | 0 | fee materialized |
| `raydium_cpmm.collect_protocol_fee` | 15 | `k_sol_fee_events` | 15 | 0 | fee materialized |
| `raydium_cpmm.create_amm_config` | 6 | `k_sol_pool_admin_events` | 6 | 0 | admin materialized |
| `raydium_cpmm.create_permission_pda` | 4 | `k_sol_pool_admin_events` | 4 | 0 | admin materialized |
| `raydium_cpmm.deposit` | 11 | `k_sol_liquidity_events` | 11 | 0 | liquidity add materialized |
| `raydium_cpmm.initialize` | 5 | `k_sol_pool_lifecycle_events` | 5 | 0 | lifecycle materialized |
| `raydium_cpmm.initialize_with_permission` | 4 | `k_sol_pool_lifecycle_events` | 4 | 0 | lifecycle only |
| `raydium_cpmm.lp_change_event` | 25 | `k_sol_liquidity_events` | 25 | 0 | liquidity materialized, `changeType` bidirectionnel |
| `raydium_cpmm.swap_base_input` | 750 | `k_sol_trade_events` | 482 | 482 | trade materialized for OK/actionable tx |
| `raydium_cpmm.swap_base_output` | 25 | `k_sol_trade_events` | 17 | 17 | trade materialized for OK/actionable tx |
| `raydium_cpmm.swap_event` | 529 | `k_sol_dex_decoded_events_only` | 0 | 0 | audit-only, no duplicate trade |
| `raydium_cpmm.update_amm_config` | 13 | `k_sol_pool_admin_events` | 13 | 0 | admin materialized |
| `raydium_cpmm.withdraw` | 14 | `k_sol_liquidity_events` | 14 | 0 | liquidity remove materialized |
| `raydium_cpmm.instruction_audit` | 3 | `k_sol_dex_decoded_events_only` | 0 | 0 | unknown audit-only |
Replay final observé :
```text
1124 replayed
561 trades
50 liquidity
9 lifecycle
2224 candle upserts
```
Le total liquidity correspond à :
```text
deposit 11
withdraw 14
lp_change_event 25
-------------------
total 50
```
## `lp_change_event`
`lp_change_event` est un event bidirectionnel :
- `changeType = 0` : add/deposit liquidity ;
- `changeType = 1` : remove/withdraw liquidity.
La coverage statique utilise donc `event_family = liquidity`, pas `liquidity_add`. La matérialisation résout le sens au niveau payload. Les events qui ne contiennent pas directement les mints sont enrichis via le contexte pool/pair local ou via le sibling `deposit` / `withdraw` déjà matérialisé dans la même transaction/replay.
Validation finale :
```text
changeType 0 -> 11 decoded / 11 liquidity / 0 trade
changeType 1 -> 14 decoded / 14 liquidity / 0 trade
```
## `initialize_with_permission`
`initialize_with_permission` est traité comme pool lifecycle only.
Validation finale :
```text
raydium_cpmm.initialize 5 decoded / 5 lifecycle / 0 admin / 0 trade
raydium_cpmm.initialize_with_permission 4 decoded / 4 lifecycle / 0 admin / 0 trade
```
Le cleanup de matérialisation supprime les anciennes lignes admin dérivées si elles existent déjà dans la base.
## Entrées non observées
Solscan avec filtre `instruction=` n'a pas retourné de transaction locale utile pour :
- `close_permission_pda` / `9c5420764587467b` ;
- `update_pool_status` / `82576c062ee0757b`.
Ces entrées restent donc :
```text
upstream_git_mapped_unverified
```
Absence Solscan ne signifie pas absence on-chain absolue, surtout si l'index UI ne couvre pas tout l'historique. Cela suffit cependant pour ne pas les promouvoir sans corpus local.
## Instruction audit inconnue
Le discriminator suivant a été observé localement :
```text
40f4bc78a7e9690a
```
Il produit actuellement `raydium_cpmm.instruction_audit` avec `tradeCandidate=false` / `candleCandidate=false`. Il n'est pas nommé dans la tranche `0.7.48`, faute de preuve upstream/corpus suffisante.
## Recherche Solscan retenue
La page programme Solscan et l'onglet Program IDL sont utiles pour accélérer la recherche :
```text
https://solscan.io/account/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C#programIdl
```
Le filtre `instruction=<discriminator>` est documenté comme méthode pratique de découverte de signatures à backfiller localement, par exemple :
```text
https://solscan.io/account/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C?instruction=f223c68952e1f2b6&instruction=b712469c946da122&hide_spam=true&hide_failed=true&show_related=false&sort=desc
```
Solscan reste une aide de recherche, pas une source de vérité métier.
## Table technique ajoutée
`k_sol_instruction_observations` est ajoutée comme table technique d'index local. Elle permet de retrouver les signatures observées par `decoder_code`, `instruction_name` et `discriminator_hex`, sans créer de nouvelle table métier.
Exemple :
```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_cpmm'
GROUP BY instruction_name, discriminator_hex
ORDER BY observed_count DESC;
```
## Invariants validés
- `swap_event` ne produit aucun trade/candle.
- `deposit`, `withdraw`, `lp_change_event`, fees, admin/config et lifecycle gardent `trade_count=0`.
- Les transactions failed restent non matérialisées en trade/candle.
- Les side effects SPL Token / Token-2022 (`burn`, `transfer`, `transferChecked`, `closeAccount`) restent hors decoder métier CPMM direct et devront passer par une future table transversale si plusieurs DEX le justifient.
- Aucun program id n'est promu sans corpus local.
## État de clôture
`0.7.48 raydium_cpmm` est clôturable avec deux entrées connues mais non observées :
```text
close_permission_pda
update_pool_status
```
La prochaine tranche fonctionnelle est `0.7.49 raydium_clmm`.
## Addendum `0.7.50-pre-r2` — cpi_event et audit `40f4bc78a7e9690a`
La re-vérification CPMM ajoute explicitement `cpi_event` à la matrice coverage locale avec le discriminant Carbon `e445a52e51cb9a1d`. Cette entrée est un transport Anchor/CPI et reste `k_sol_dex_decoded_events_only`.
Le discriminant observé localement `40f4bc78a7e9690a` est classé comme `raydium_cpmm.anchor_idl_instruction`, avec `event_family=idl_management` et `expected_db_target=k_sol_dex_decoded_events_only`. Les signatures inspectées montrent `Program log: Instruction: IdlCreateAccount` et `Program log: Instruction: IdlCloseAccount` sur le compte `anchor:idl`; il ne correspond donc pas au `cpi_event` Carbon et ne doit pas être matérialisé dans les tables métier.
Trace SQL ajouté : `validation_sql/SQL_TRACE_RAYDIUM_CPMM_AUDIT_40F_0_7_50_PRE_R2.sql` liste les signatures, slots, index d'instruction, comptes et données associées à `40f4bc78a7e9690a`.

View File

@@ -0,0 +1,74 @@
<!-- file: docs/reports/RAYDIUM_CPMM_UPSTREAM_COVERAGE_REVIEW_PRE22.md -->
# Raydium CPMM upstream coverage review — 0.7.49-pre.22
## Scope
Compared local `raydium_cpmm` coverage against the currently referenced upstream surfaces:
- Solscan program IDL for `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C`.
- `sevenlabs-hq/carbon` `raydium-cpmm-decoder`.
- `0xfnzero/sol-parser-sdk` `idl/raydium_cpmm.json`.
- `pinax-network/substreams-solana-idls` `src/raydium/cpmm`.
- Raydium official `raydium-cp-swap` source.
## Local CPMM coverage entries
Local registry currently lists 16 `raydium_cpmm` entries:
### Instructions
- `close_permission_pda``9c5420764587467b`
- `collect_creator_fee``1416567bc61cdb84`
- `collect_fund_fee``a78a4e95dfc2067e`
- `collect_protocol_fee``8888fcddc2427e59`
- `create_amm_config``8934edd4d7756c68`
- `create_permission_pda``878802d889a9b5ca`
- `deposit``f223c68952e1f2b6`
- `initialize``afaf6d1f0d989bed`
- `initialize_with_permission``3f37fe4131b25979`
- `swap_base_input``8fbe5adac41e33de`
- `swap_base_output``37d96256a34ab4ad`
- `update_amm_config``313cae889a1c74c8`
- `update_pool_status``82576c062ee0757b`
- `withdraw``b712469c946da122`
### Anchor / Program-data events
- `lp_change_event``79a3cdc939da753c`
- `swap_event``40c6cde8260871e2`
## Upstream comparison
Carbon `raydium-cpmm-decoder` exposes the same 14 instruction modules and the two event-like discriminator entries, `lp_change_event` and `swap_event`.
`sol-parser-sdk` `idl/raydium_cpmm.json` exposes the core CPMM instruction set (`createAmmConfig`, `updateAmmConfig`, `updatePoolStatus`, `collectProtocolFee`, `collectFundFee`, `initialize`, `deposit`, `withdraw`, `swapBaseInput`, `swapBaseOutput`) and IDL events `LpChangeEvent` and `SwapEvent`. The local registry also includes the permission and creator-fee entries present in Carbon / Raydium source.
The official Raydium `raydium-cp-swap` source lists the CPMM program ID and the main program instructions including admin/config, fee collection, permission PDA, initialize, initialize with permission, deposit, withdraw, swap base input, and swap base output.
## Finding
No missing CPMM instruction/event discriminator was identified relative to the reviewed Carbon / Raydium / fnzero / Pinax surfaces available during this check.
## Current local caveat
CPMM remains covered by the earlier 0.7.48 tranche. The useful final validation remains DB-side:
```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_cpmm'
ORDER BY entry_kind, entry_name, discriminator_hex;
```
Any future upstream addition should appear as a new entry in Carbon/Solscan/IDL and should be added to `upstream_registry_generated.rs`, `known_local_event_kind` only after local decoder support exists, and then validated with local corpus evidence.

View File

@@ -0,0 +1,233 @@
<!-- file: docs/reports/RAYDIUM_LAUNCHPAD_EVENT_COVERAGE_REPORT.md -->
# Raydium Launchpad event coverage report — `0.7.50`
## Scope
`0.7.50` opens the `raydium_launchpad` tranche after the functional closure of `0.7.49 raydium_clmm`.
Local canonical decoder/surface code:
```text
raydium_launchpad
```
Canonical program id:
```text
LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj
```
The legacy local name `raydium_launchlab` is not kept in the public Rust API. Coverage rows, upstream registry rows, launch origin entries, and support matrix rows use `raydium_launchpad`.
## Sources used
Primary source hints for this tranche:
- Carbon decoder registry/source: `sevenlabs-hq/carbon/decoders/raydium-launchpad-decoder`.
- Solscan Program IDL/account page: `https://solscan.io/account/LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj#programIdl`.
- fnzero IDL sources: `sol-parser-sdk` / `solana-program-idls` listings, including `raydium_launchpad.json` and separate `raydium_pool_v4.json` as an audit-only source.
- Raydium SDK Launchpad examples for account-shape hints only.
These sources are not treated as final business proof. Promotion still requires local corpus observation and SQL validation.
## Bootstrap implementation delta
Implemented in this delta:
- `RAYDIUM_LAUNCHPAD_PROGRAM_ID` added as the canonical public constant.
- Upstream generated registry rows normalized from `raydium_launchlab` to `raydium_launchpad`.
- Built-in launch surface code normalized to `raydium_launchpad`.
- DEX support/catalog entries normalized to `raydium_launchpad`.
- Raydium instruction audit fallback now recognizes Launchpad program id.
- Launchpad mapped instruction fallback added for locally listed Launchpad discriminators.
- Coverage target override keeps Launchpad rows `decoded_events_only` until corpus promotion.
- SQL validation file added for the `0.7.50` tranche.
## Listed Launchpad entries
The local upstream registry now lists one program entry plus the following 26 discriminator entries.
| Entry kind | Entry name | Discriminator | Initial family | Initial DB target |
|---|---:|---:|---|---|
| instruction | `buy_exact_in` | `faea0d7bd59c13ec` | swap | decoded_events_only |
| instruction | `buy_exact_out` | `18d3742869039938` | swap | decoded_events_only |
| instruction | `claim_creator_fee` | `1a618acb84ab8dfc` | fee | decoded_events_only |
| instruction | `claim_platform_fee` | `9c27d0874ced3d48` | fee | decoded_events_only |
| instruction | `claim_platform_fee_from_vault` | `75f1c6a8f8da501d` | fee | decoded_events_only |
| event | `claim_vested_event` | `15c2725778d3e220` | fee/vesting audit | decoded_events_only |
| instruction | `claim_vested_token` | `3121681ebd9d4f23` | fee/vesting audit | decoded_events_only |
| instruction | `collect_fee` | `3cadf767045d8230` | fee | decoded_events_only |
| instruction | `collect_migrate_fee` | `ffba96dfeb76c9ba` | fee/migration audit | decoded_events_only |
| instruction | `create_config` | `c9cff3724b6f2fbd` | admin_config | decoded_events_only |
| instruction | `create_platform_config` | `b05ac4affd71dc14` | admin_config | decoded_events_only |
| instruction | `create_vesting_account` | `81b2020dd9ace6da` | account_create/vesting audit | decoded_events_only |
| event | `create_vesting_event` | `96980bb334d2bf7d` | account_create/vesting audit | decoded_events_only |
| instruction | `initialize` | `afaf6d1f0d989bed` | pool_create/launch | decoded_events_only |
| instruction | `initialize_v2` | `4399af27da102620` | pool_create/launch | decoded_events_only |
| instruction | `initialize_with_token_2022` | `25be7ede2c9aab11` | pool_create/launch | decoded_events_only |
| instruction | `migrate_to_amm` | `cf52c091fecf91df` | migration | decoded_events_only |
| instruction | `migrate_to_cpswap` | `885cc8671cda908c` | migration | decoded_events_only |
| event | `pool_create_event` | `97d7e20976a173ae` | pool_create | decoded_events_only |
| instruction | `remove_platform_curve_param` | `1b1e3ea95de01891` | admin_config | decoded_events_only |
| instruction | `sell_exact_in` | `9527de9bd37c981a` | swap | decoded_events_only |
| instruction | `sell_exact_out` | `5fc8472208090ba6` | swap | decoded_events_only |
| event | `trade_event` | `bddb7fd34ee661ee` | swap | decoded_events_only |
| instruction | `update_config` | `1d9efcbf0a53db63` | admin_config | decoded_events_only |
| instruction | `update_platform_config` | `c33c4c81922d438f` | admin_config | decoded_events_only |
| instruction | `update_platform_curve_param` | `8a908afadc800439` | admin_config | decoded_events_only |
Notes:
- The buy/sell instruction account hints currently use account index `4` as candidate pool account and indexes `9`/`10` as candidate token mints, based on Carbon/Raydium Launchpad account shape hints. This is an audit helper, not a materialization proof.
- Fee/admin/migration/vesting entries intentionally do not infer pool/token accounts until corpus confirms the account semantics.
- Program-data transport is represented by `cpi_event`; embedded events are decoded by their own discriminators and materialized only when their event family has a validated target.
## Family audit matrix
| Family | Launchpad status in `0.7.50` final | Decision |
|---|---|---|
| swap | `trade_event` materialized as trades/candles; buy/sell instructions materialized as launch breadcrumbs. | No duplicate trades from instruction breadcrumbs. |
| pool_create | `initialize`, `initialize_v2`, `initialize_with_token_2022`, `pool_create_event`. | Pool lifecycle/catalogue materialized when transaction succeeded. |
| add_liquidity | No direct Launchpad entry confirmed. | Non-applicable unless local corpus proves direct Launchpad liquidity instruction. |
| remove_liquidity | No direct Launchpad liquidity remove entry confirmed. | Non-applicable unless local corpus proves direct Launchpad liquidity instruction. |
| position_open | No direct Launchpad position instruction confirmed. | Non-applicable. |
| position_close | No direct Launchpad position instruction confirmed. | Non-applicable. |
| fee | claim/collect fee entries listed. | Fee table materialization enabled for observed successful transactions. |
| reward | No direct reward instruction confirmed. | Non-applicable unless local corpus proves otherwise. |
| admin/config | create/update config and platform curve/config entries listed. | Pool admin materialization enabled for observed successful transactions. |
| mint | Token minting may appear as SPL Token/Token-2022 side effect. | Not `raydium_launchpad.*` without direct program proof. |
| burn | Token burn may appear as SPL Token/Token-2022 side effect. | Not `raydium_launchpad.*` without direct program proof. |
| transfer | Transfers are expected as SPL Token/Token-2022 side effects. | Not `raydium_launchpad.*` without direct program proof. |
| account_create / vesting | `create_vesting_account`, `create_platform_vesting_account`, vesting events. | Launch event materialization enabled for observed successful transactions; unobserved events remain mapped. |
| account_close | No direct Launchpad account close confirmed. | Non-applicable. |
| wrap_sol | No direct Launchpad wrap SOL confirmed. | Side effect only unless corpus proves direct instruction. |
| unwrap_sol | No direct Launchpad unwrap SOL confirmed. | Side effect only unless corpus proves direct instruction. |
| order_place | No orderbook surface confirmed. | Non-applicable. |
| order_cancel | No orderbook surface confirmed. | Non-applicable. |
| order_fill | No orderbook surface confirmed. | Non-applicable. |
| consume_events | No orderbook surface confirmed. | Non-applicable. |
| settle_funds | No orderbook surface confirmed. | Non-applicable. |
| vault_deposit | No direct vault deposit confirmed. | Non-applicable. |
| vault_withdraw | No direct vault withdraw confirmed. | Non-applicable. |
| lock | No direct lock confirmed. | Non-applicable. |
| unlock | No direct unlock confirmed. | Non-applicable. |
| launch | initialize/pool_create path listed. | Decode/audit only. |
| migration | `migrate_to_amm`, `migrate_to_cpswap`, `collect_migrate_fee` listed. | Decode/audit only. Destination DEX materialization must be proven locally. |
| stake | No direct stake confirmed. | Non-applicable. |
| unstake | No direct unstake confirmed. | Non-applicable. |
| unknown/unmapped audit | `raydium_launchpad.instruction_audit` retained for unmatched program instructions. | Must trend toward zero for locally covered discriminators after backfill/replay. |
## SQL validation expectations
After targeted backfill and replay:
1. `k_sol_dex_event_coverage_entries` should contain the Launchpad program entry and discriminator entries.
2. Mapped entries should have `local_event_kind = raydium_launchpad.<entry_name>` and initial `proof_status = upstream_git_mapped_unverified` until observed.
3. Locally observed instructions should increment `k_sol_instruction_observations` for `decoder_code = raydium_launchpad`.
4. `upstream_git.instruction_match` fallback rows for `upstreamDecoderCode = raydium_launchpad` should be zero for locally covered instruction discriminators.
5. `raydium_launchpad.*` rows must not produce trades/candles unless a later corpus-backed patch explicitly promotes a specific event.
6. Failed transactions may be decoded/audited, but must not be materialized in trade/candle tables.
Validation file:
```text
validation_sql/SQL_VALIDATION_RAYDIUM_LAUNCHPAD_0_7_50.sql
```
## Suggested targeted Solscan discovery loop
For each discriminator:
```text
https://solscan.io/account/LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj?instruction=<DISCRIMINATOR>&hide_spam=true&hide_failed=true&show_related=false&sort=desc
```
Then:
1. copy a small batch of recent non-failed signatures;
2. backfill through Demo2 textarea batch;
3. replay with `forceDexDecode=yes` and `deferInstructionObservations=yes`;
4. run the validation SQL;
5. promote only entries whose local payload and account semantics are proven.
## `raydium_pool_v4.json` audit status
The current workspace archive does not contain a local `raydium_pool_v4.json` copy. External fnzero IDL listings expose a separate `raydium_pool_v4.json` beside `raydium_launchpad.json`, but this delta does not confirm its program id or business role.
Decision for `0.7.50`:
- do not promote `raydium_pool_v4` as a DEX/surface;
- keep `0.7.53 raydium_pool_v4 audit / program-id decision` conditional;
- require program id confirmation and local corpus before any roadmap promotion.
## Current limitations
This delta was prepared from the provided archive only. No live RPC backfill, fresh SQLite replay, `cargo fmt`, `cargo test`, or `cargo clippy` could be executed in the current environment because the Rust toolchain is unavailable here. The SQL and code paths are prepared for local validation in the normal project environment.
## Local corpus snapshot from first 0.7.50 backfill
Observed after targeted Demo2 backfills and pool backfill on a fresh 0.7.50 DB:
- coverage listed entries: `27`;
- decoded/local mapped entries: `26`;
- observed entries: `21`;
- materialized entries: `0`;
- total observed coverage count: `672`;
- total materialized count: `0`;
- trade count: `0`;
- residual `upstream_git.instruction_match` for `raydium_launchpad`: `0`;
- residual `raydium_launchpad.instruction_audit`: `287`;
- residual audit discriminators: `e445a52e51cb9a1d` (`276`), `9247ad4562130f6a` (`10`), `a25b92c75d85eaed` (`1`).
The `e445a52e51cb9a1d` selector is handled as Anchor self-CPI event transport. It is not promoted as a Raydium Launchpad business instruction. The two low-count residual discriminators remain local-corpus audit-only until an IDL/upstream mapping is confirmed.
## pre3 correction — Demo3 preset and Launchpad pool catalog
The first replay after pre2 confirmed that Anchor self-CPI selector `e445a52e51cb9a1d` carries Launchpad `trade_event` (`bddb7fd34ee661ee`) and `pool_create_event` (`97d7e20976a173ae`). pre3 therefore decodes those two self-CPI event rows as direct `raydium_launchpad.*` events instead of leaving them under `raydium_launchpad.instruction_audit`. `trade_event` remains audit/decoded-only and is still not promoted to `k_sol_trade_events` or candles.
pre3 also fixes the Launchpad `initialize`, `initialize_v2` and `initialize_with_token_2022` account mapping using the Carbon account shape: `pool_state` index 5, `base_mint` index 6 and `quote_mint` index 7. These initialize rows are now routed to business-level pool detection as `raydium_launchpad` bonding-curve pools with pending status, which should allow pool `6HLQPoLrzX6LqePRiXQ1GGs2Dd9K3dp9VhTSHBugYzzZ` to appear in the local catalog after a forced replay when its initialize transaction is present locally.
Demo3 now exposes a `Raydium Launchpad` preset with program id `LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj`.
## Final `0.7.50` closure snapshot
Validated closure state reported by local replay:
- `cargo test -p kb_lib`: 404 passed, 0 failed.
- Local replay: 437 replayed, 437 ledger upserts, 30 unsafe ledger rows, 256 trades, 115 lifecycle rows, 1024 candle upserts, 6205 instruction observations.
- Launchpad catalogue: 58 tokens, 58 pools, 58 pairs after replay.
- Coverage normalization: no ambiguous `unknown` family remains; only the synthetic `program` row may have an empty family.
- `trade_event`: 260 decoded, 250 successful materialized trades; 10 failed transactions intentionally not materialized.
- `buy_exact_*` / `sell_exact_*`: materialized as `k_sol_launch_events` swap-instruction breadcrumbs, not as trades.
- `cpi_event`: kept as `cpi_transport` / decoded-only; embedded events are decoded by direct event discriminator.
- Successful `trade_event` rows without materialized `k_sol_trade_events`: zero.
Post-closure recheck assets added:
- `validation_sql/SQL_VALIDATION_RAYDIUM_CPMM_0_7_50_PRE_R2.sql`
- `validation_sql/SQL_VALIDATION_RAYDIUM_CLMM_0_7_50_PRE_R2.sql`
- `docs/SOLSCAN_ACCOUNT_SOURCE_MATRIX.md`
- `kb_lib::SOLSCAN_ACCOUNT_SOURCES`
## Final cleanup note — CPMM residual audit after 0.7.50 recheck
During the 0.7.50 post-Launchpad recheck, the CPMM residual audit query still showed three `raydium_cpmm.instruction_audit` rows for discriminator `40f4bc78a7e9690a` even though the same discriminator is now locally mapped as `raydium_cpmm.anchor_idl_instruction`.
The final cleanup patch makes the deletion FK-safe by unlinking `k_sol_instruction_observations.decoded_event_id` before deleting the legacy audit rows. It also repeats the CPMM cleanup after coverage refresh and refreshes coverage again if rows were removed.
Expected final state after replay:
```text
raydium_cpmm.instruction_audit / 40f4bc78a7e9690a = 0
raydium_cpmm decoded events without coverage row = 0
raydium_cpmm.anchor_idl_instruction remains decoded-only / idl_management
```
Validation SQL:
```text
validation_sql/SQL_VALIDATION_RAYDIUM_CPMM_AUDIT_CLEANUP_0_7_50_FINAL.sql
```

View File

@@ -0,0 +1,56 @@
<!-- file: docs/reports/RAYDIUM_POOL_V4_DECISION_NOTE.md -->
# Raydium Pool v4 Decision Note — `0.7.51`
## Décision courte
`raydium_pool_v4` ne doit pas être ouvert comme decoder autonome dans `0.7.51`.
Statut retenu :
```text
Option C — IDL ambiguë / strategy-pool wrapper sans corpus local suffisant.
```
Conséquence : `raydium_pool_v4` reste une source d'audit/comparaison pour `raydium_amm_v4`. Toute promotion en tranche dédiée exige un program id prouvé localement, des observations dans `k_sol_instruction_observations`, des decoded events locaux et une absence de fallback upstream inexpliqué.
## Comparaison synthétique
| Source | Nom / rôle constaté | Indices structurants | Décision locale |
|---|---|---|---|
| `idl/raydium_amm_v4.json` | `raydium_amm` | Instructions AMM v4 legacy : `initialize`, `initialize2`, `deposit`, `withdraw`, `swapBaseIn`, `swapBaseOut`, `monitorStep`, `setParams`. | Source principale pour `raydium_amm_v4`. |
| `idls/raydium_amm_v4.json` | `raydium_amm` | Variante parallèle à comparer ligne à ligne avec `idl/`. | Source principale complémentaire. |
| `idl/raydium_pool_v4.json` | `Raydium Liquidity Pool V4` | Entrées orientées stratégie/pool wrapper : `initializeStrategy`, comptes `strategyState`, `strategyAuthority`, `lendingProgramId`; contient aussi des noms comme `swapBaseIn`. | Audit uniquement. Ne pas promouvoir. |
| `idls/raydium_pool_v4.json` | `Raydium Liquidity Pool V4` | Même famille de signaux que `idl/raydium_pool_v4.json` à vérifier localement. | Audit uniquement. |
## Raisons de non-promotion
1. `raydium_pool_v4` ne prouve pas encore un program id local autonome dans le workspace.
2. La présence de noms communs (`swapBaseIn`, comptes OpenBook) ne suffit pas à conclure que la surface est le program id AMM v4 canonique `675kPX...`.
3. Les entrées `initializeStrategy`, `strategyState`, `strategyAuthority` et `lendingProgramId` indiquent un rôle potentiellement distinct : strategy, wrapper, pool manager, lending ou ancienne ABI composite.
4. Aucune ligne locale `k_sol_instruction_observations` / `k_sol_dex_decoded_events` / `k_sol_dex_event_coverage_entries.local_event_kind` ne justifie une tranche autonome au moment de l'ouverture `0.7.51`.
## Règle de décision future
- Si `raydium_pool_v4` correspond finalement au même program id AMM v4 ou à un layout alternatif compatible, intégrer les discriminants/layouts validés dans `raydium_amm_v4`.
- Si `raydium_pool_v4` correspond à un autre program id / wrapper / strategy / lending surface, créer une tranche dédiée seulement après corpus local.
- Si l'IDL reste ambiguë, conserver l'entrée en roadmap comme audit conditionnel sans decoder runtime.
## SQL local attendu avant toute promotion
Une future promotion doit au minimum montrer :
```sql
SELECT
decoder_code,
instruction_name,
discriminator_hex,
COUNT(*) AS observed_count,
COUNT(DISTINCT signature) AS tx_count
FROM k_sol_instruction_observations
WHERE decoder_code IN ('raydium_amm_v4', 'raydium_pool_v4')
GROUP BY decoder_code, instruction_name, discriminator_hex
ORDER BY decoder_code, observed_count DESC;
```
Puis une preuve de decoded events locaux, de coverage entries mappées et d'absence de fallback upstream résiduel.

View File

@@ -0,0 +1,164 @@
<!-- file: docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md -->
# Raydium Stable Swap event coverage report — 0.7.52 final
## Scope
`0.7.52` closes the `raydium_stable_swap` tranche after `0.7.51 raydium_amm_v4`.
Canonical local decoder code:
```text
raydium_stable_swap
```
Canonical program id validated by local corpus:
```text
5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h
```
Stable Swap is handled as a Raydium legacy AMM-style program with a one-byte instruction discriminator layout. Anchor-like 8-byte discriminants remain upstream discovery evidence only and are not business proof.
## Final implementation status
Implemented and locally validated:
- `kb_lib/src/dex/raydium_stable_swap.rs`.
- `RaydiumStableSwapDecoder` re-exported through `kb_lib/src/dex.rs` and `kb_lib/src/lib.rs`.
- Stable Swap route in `DexDecodeService` before generic Raydium instruction-audit preservation.
- One-byte Stable Swap instruction observation support.
- Coverage entries for all locally observed Stable Swap discriminants `00..0d`.
- Materialization into lifecycle/liquidity/fee/admin/orderbook/trade tables when the local corpus proves a safe target.
- Swap materialization from exact vault balance deltas only.
- Validation SQL in `validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql`.
## Instruction surface
| entry | discriminator | family | final target | local event kind | final status |
|---|---:|---|---|---|---|
| `initialize` | `00` | `pool_create` | `k_sol_pool_lifecycle_events` | `raydium_stable_swap.initialize` | observed/materialized when context complete |
| `init_model_data` | `01` | `model_setup` | decoded-only | `raydium_stable_swap.init_model_data` | observed decoded-only / explained |
| `update_model_data` | `02` | `admin_config` | `k_sol_pool_admin_events` | `raydium_stable_swap.update_model_data` | observed/materialized |
| `deposit` | `03` | `liquidity_add` | `k_sol_liquidity_events` | `raydium_stable_swap.deposit` | observed/materialized |
| `withdraw` | `04` | `liquidity_remove` | `k_sol_liquidity_events` | `raydium_stable_swap.withdraw` | observed/materialized |
| `monitor_step` | `05` | `order_place` | `k_sol_orderbook_events` | `raydium_stable_swap.monitor_step` | observed/materialized |
| `set_params` | `06` | `admin_config` | `k_sol_pool_admin_events` | `raydium_stable_swap.set_params` | observed/materialized |
| `withdraw_pnl` | `07` | `fee` | `k_sol_fee_events` | `raydium_stable_swap.withdraw_pnl` | observed/materialized |
| `withdraw_srm` | `08` | `fee` | `k_sol_fee_events` | `raydium_stable_swap.withdraw_srm` | observed/materialized when context complete |
| `swap_base_in` | `09` | `swap` | `k_sol_trade_events` only from vault deltas | `raydium_stable_swap.swap_base_in` | observed, materialized for successful swaps with exact deltas |
| `pre_initialize` | `0a` | `pool_create` | decoded-only or lifecycle when complete | `raydium_stable_swap.pre_initialize` | observed decoded-only / explained in current corpus |
| `swap_base_out` | `0b` | `swap` | `k_sol_trade_events` only from vault deltas | `raydium_stable_swap.swap_base_out` | observed, materialized for successful swaps with exact deltas |
| `simulate_info` | `0c` | `cpi_transport` | decoded-only | `raydium_stable_swap.simulate_info` | observed decoded-only / explained |
| `admin_cancel_orders` | `0d` | `orderbook_admin` | `k_sol_orderbook_events` | `raydium_stable_swap.admin_cancel_orders` | observed/materialized when context complete |
| `swap_event` | `40c6cde8260871e2` | `cpi_transport` | decoded-only | `raydium_stable_swap.swap_event` | upstream mapped, not observed in local corpus |
## Swap amount policy
Stable Swap instruction arguments are retained as instruction bounds, but they are not sufficient for trade/candle materialization:
```text
swap_base_in:
amountInRaw = exact input argument
minimumAmountOutRaw = slippage lower bound, not exact output
swap_base_out:
amountOutRaw = requested output argument
maxAmountInRaw = slippage upper bound, not exact input
```
Therefore, `swap_base_in` and `swap_base_out` materialize as trades/candles only when exact base/quote amounts are inferred from vault balance deltas:
```text
amountSource = stable_swap_vault_balance_delta
```
Instruction-bound-only swaps remain decoded-only:
```text
amountSource = stable_swap_instruction_bounds_only
tradeCandidate = false
candleCandidate = false
```
For failed transactions the skip reasons are:
```text
skipTradeReason = failed_transaction
skipCandleReason = failed_transaction
```
For successful transactions where exact vault deltas cannot be proven, the expected skip reason is:
```text
stable_swap_exact_amounts_unresolved
```
The final local corpus has no successful unresolved Stable Swap swap.
## Final local validation snapshot
Latest confirmed local commands:
```text
cargo test -p kb_lib
407 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
cargo clippy -p kb_lib --all-targets -- -D warnings
ok
```
Latest replay snapshot:
```text
replayed=298
decode_skipped=0
ledger_upserts=298
unsafe_ledger_rows=258
trades=290
liquidity=16
lifecycle=4
token_account=0
candle_upserts=1160
instructionObservations=5317
resetDeleted=1059
catalog=40 tokens / 59 pools / 59 pairs
```
Stable Swap swap closure:
| event kind | amount source | tx status | decoded | trades |
|---|---|---|---:|---:|
| `raydium_stable_swap.swap_base_in` | `stable_swap_instruction_bounds_only` | failed | 27 | 0 |
| `raydium_stable_swap.swap_base_in` | `stable_swap_vault_balance_delta` | success | 171 | 171 |
| `raydium_stable_swap.swap_base_out` | `stable_swap_instruction_bounds_only` | failed | 2 | 0 |
| `raydium_stable_swap.swap_base_out` | `stable_swap_vault_balance_delta` | success | 4 | 4 |
UI smoke evidence after the vault-delta correction:
```text
pair 27, timeframe 60s -> 70 candles
pair 30, timeframe 60s -> 44 candles
```
## Final invariant status
Validated as clean on the local corpus:
- residual `raydium_stable_swap.instruction_audit`: empty;
- residual `upstream_git.instruction_match` for covered local entries: empty;
- decoded-without-coverage: empty;
- non-swap materialized as trade: empty;
- failed transaction materialized as business trade: empty;
- multi-target materialization: empty;
- successful non-materialized swaps without skip reason: empty;
- Stable Swap successful swaps with `stable_swap_vault_balance_delta`: `trade_count = decoded_count`;
- Stable Swap instruction-bound-only swaps: failed only, `trade_count = 0`.
## Closure decision
`0.7.52 raydium_stable_swap` is closed for the currently observed local corpus.
The decoder has detected all locally observed Stable Swap instruction discriminants, materialized every event that can safely be materialized, and preserved non-materializable/failed events as decoded-only with explicit reasons.
Future work is not a blocker for `0.7.52` and should be handled as a later tranche if a new local corpus reveals additional discriminants or a direct, reliable `swap_event` path.

View File

@@ -0,0 +1,219 @@
# SQLite DB Transaction Merger — 0.7.58
## Statut
`0.7.58` introduit un outil CLI de fusion de corpus SQLite transactionnels pour construire une base consolidée de non-régression (`final.db` ou `final.next.db`) à partir de bases dédiées par DEX/surface.
Le merger ne lance pas de RPC, ne backfille pas, ne redécode pas et ne matérialise pas pendant la fusion. Il copie seulement le corpus brut nécessaire au replay local.
## Emplacement
```text
kb_tools/
Cargo.toml
src/bin/kb_db_merge.rs
```
Le package `kb_tools` est membre du workspace principal.
## Commandes types
Dry-run sur un output cible :
```bash
cargo run -p kb_tools --bin kb_db_merge -- \
--output ./final.next.db \
--input ./final.db \
--input ./corpus/pump_swap.db \
--input ./corpus/pump_fees.db \
--mode raw-corpus \
--dry-run
```
Merge réel dans une nouvelle base :
```bash
cargo run -p kb_tools --bin kb_db_merge -- \
--output ./final.next.db \
--input ./final.db \
--input ./corpus/new_dex.db \
--mode raw-corpus \
--replace-output
```
Merge dans une copie explicite de `final.db` :
```bash
cargo run -p kb_tools --bin kb_db_merge -- \
--merge-into-copy-of ./final.db \
--output ./final.next.db \
--input ./corpus/new_dex.db \
--mode raw-corpus \
--replace-output
```
## Modes
### `raw-corpus`
Mode par défaut.
Copie uniquement :
```text
k_sol_chain_transactions
k_sol_chain_instructions
```
Les tables décodées ou matérialisées ne sont pas copiées, car leur contenu dépend de la version active des decoders/materializers et doit être reconstruit par replay local.
### `signatures-only`
Alimente `k_sol_db_merge_signature_staging` avec `source_id`, `signature`, `slot` et `source_transaction_id`.
Ce mode sert à auditer ou préparer des backfills contrôlés sans copier les transactions complètes.
### `full-copy-safe`
Le mode est exposé dans le CLI mais reste explicitement refusé dans `0.7.58`. Il ne doit devenir utilisable que si les versions de schéma, les versions logiques des decoders et les remappages de foreign keys sont prouvés compatibles.
## Tables de provenance
Le schéma `kb_lib` ajoute :
```text
k_sol_db_merge_sources
k_sol_db_merge_transactions
k_sol_db_merge_conflicts
k_sol_db_merge_signature_staging
```
Ces tables permettent de relier chaque ligne copiée ou ignorée à sa source et de journaliser les conflits au lieu décraser silencieusement.
## Déduplication
Lidentité canonique est :
```text
signature
```
Règles :
- signature absente de loutput : copie transaction + instructions enfants ;
- signature déjà présente et identique : provenance `duplicate_skipped` ;
- signature déjà présente mais différente : insertion dans `k_sol_db_merge_conflicts` ;
- `--conflict-policy fail` : arrêt au premier conflit journalisé ;
- `--conflict-policy prefer-complete` : remplacement uniquement si le corpus entrant obtient un score de complétude supérieur ;
- `--conflict-policy record` : journalisation sans remplacement.
## Inspection de schéma
Chaque source est inspectée avant traitement :
```sql
SELECT name, sql FROM sqlite_master WHERE type = 'table';
PRAGMA table_info(k_sol_chain_transactions);
PRAGMA table_info(k_sol_chain_instructions);
```
Pour `raw-corpus`, une source est refusée si elle ne contient pas les tables et colonnes minimales nécessaires au replay local.
Les erreurs mentionnent :
```text
source DB
missing table ou missing column
mode demandé
```
## Replay attendu après merge
Après merge réel de `final.next.db`, rejouer localement avec :
```text
metadata=no
skipDexDecode=no
forceDexDecode=yes
deferInstructionObservations=yes
```
Objectif : reconstruire toutes les tables dérivées avec les decoders/materializers courants et détecter les régressions cross-surface.
## SQL de validation
Fichiers ajoutés :
```text
validation_sql/SQL_VALIDATION_DB_MERGE_0_7_58.sql
validation_sql/SQL_VALIDATION_CROSS_DEX_REGRESSION_0_7_58.sql
```
Gates minimaux merge :
- aucune signature dupliquée ;
- aucune instruction orpheline ;
- aucune relation parent/child orpheline ;
- conflits listés et classifiés ;
- provenance source lisible.
Gates minimaux anti-régression après replay :
- surfaces closes Pump/Raydium/Meteora présentes dans le rollup ;
- failed transactions sans matérialisation actionable ;
- non-swap sans trade ;
- résidus decoded-without-target explicitement classés ;
- sentinelle PumpSwap/PumpFees pour les transactions cross-surface.
## Workflow futur
Pour chaque nouveau DEX ou surface :
1. créer une base vide dédiée ;
2. backfiller les signatures/pools nécessaires ;
3. développer decoder/materializer sur cette base ;
4. clore avec les SQL propres du DEX ;
5. fusionner dans `final.next.db` ;
6. rejouer `final.next.db` avec `forceDexDecode=yes` ;
7. lancer les validations globales ;
8. promouvoir seulement si les gates sont propres.
## Surfaces à vérifier en non-régression
Minimum actif pour `0.7.58` :
```text
pump_swap
pump_fun
pump_fees
raydium_cpmm
raydium_clmm
raydium_amm_v4
raydium_stable_swap
raydium_launchpad
meteora_dbc
meteora_dlmm
```
Règle decoder associée : un payload tronqué ou incompatible sur une surface secondaire ne doit pas aborter la transaction entière si lentrée peut être ignorée proprement. Préférer `Ok(None)` + observation/debug contrôlé pour les payloads tronqués connus ; conserver `Err` pour corruption critique ou incohérence interne.
## Clôture attendue
La tranche peut être clôturée seulement après :
```text
cargo test -p kb_lib
cargo test -p kb_tools
cargo clippy -p kb_lib -- -D warnings
cargo clippy -p kb_tools -- -D warnings
```
Puis :
- dry-run merge lisible ;
- merge réel multi-source OK ;
- pas de duplicate signatures ;
- pas dinstructions orphelines ;
- conflits journalisés ;
- replay local de `final.next.db` OK ;
- validation anti-régression Pump/Raydium/Meteora exécutée et documentée.