0.7.52
This commit is contained in:
@@ -84,3 +84,4 @@
|
||||
0.7.50 - Raydium Launchpad event coverage bootstrap : normalisation locale canonique vers `raydium_launchpad`, ajout de `RAYDIUM_LAUNCHPAD_PROGRAM_ID`, synchronisation des entrées Carbon Launchpad dans le registre upstream, fallback audit/mapped decoder pour discriminants Launchpad, enrichissement audit Anchor self-CPI, maintien conservatoire en `decoded_events_only`, rapport Launchpad et SQL de validation dédiés.
|
||||
0.7.50-pre-r2 - Clôture CPMM/CLMM post-Launchpad : ajout des entrées Carbon `cpi_event` pour `raydium_cpmm` et `raydium_clmm`, ajout de `raydium_clmm.update_dynamic_fee_config`, normalisation des Program-data events CLMM, ajout de la table `k_sol_token_account_events` et de la matérialisation `create_support_mint_associated`, reclassement des familles ambiguës (`cpi_transport`, `liquidity_calculation`, `liquidity_change`, `position_open`, `pool_create`, `admin_config`, `account_create`, `idl_management`), codage du discriminant CPMM `40f4bc78a7e9690a` comme `raydium_cpmm.anchor_idl_instruction` decoded-only après inspection Solscan, et contexte de secours pour matérialisation liquidity CLMM via événements frères quand possible.
|
||||
0.7.51 - Raydium AMM v4 event coverage clôturé : decoder maximal local pour tous les discriminants officiels AMM v4 `00..11`, spécialisation des swaps `swap_base_in/out` et `swap_base_in/out_v2`, suppression durable du `raydium_amm_v4.swap` legacy, index AMM v4 en discriminant 1 octet, matérialisation validée des swaps, liquidity, lifecycle, fees, admin/config et side effects orderbook, `pre_initialize` conservé comme lifecycle audit deprecated/partial, `simulate_info` decoded-only, reset replay renforcé par `protocol_name`, validation des invariants failed/non-swap/single-target/unexplained gaps et maintien de `raydium_pool_v4` en audit conditionnel sans decoder autonome.
|
||||
0.7.52 - Raydium Stable Swap event coverage clôturé : decoder legacy 1 octet pour la surface locale `00..0d`, matérialisation lifecycle/liquidity/admin/fee/orderbook selon contexte, swaps `swap_base_in/out` matérialisés uniquement depuis deltas de vaults exacts (`stable_swap_vault_balance_delta`), conservation des bornes d’instruction comme audit-only, failed transactions decoded-only avec skip reasons, validation locale 407 tests et clippy `-D warnings` OK.
|
||||
|
||||
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.7.51"
|
||||
version = "0.7.52"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||
|
||||
41
README.md
41
README.md
@@ -78,7 +78,7 @@ non-swap CLMM avec trade_count > 0 = 0
|
||||
|
||||
Les 11 Anchor / `Program data` events CLMM restent listés en `upstream_git_unverified` car aucun corpus local ne les observe encore. Le code est préparé pour les accueillir en audit-only lorsqu’ils apparaîtront dans un corpus local, sans créer de trade/candle par défaut.
|
||||
|
||||
La tranche `0.7.51 raydium_amm_v4` est maintenant validée côté `kb_lib`. La suite de roadmap reprend avec `0.7.52 raydium_stable`, tandis que `raydium_pool_v4` reste un audit conditionnel ultérieur et ne doit pas être promu sans confirmation de program id/rôle/corpus.
|
||||
Les tranches `0.7.51 raydium_amm_v4` et `0.7.52 raydium_stable_swap` sont maintenant validées côté `kb_lib`. La suite de roadmap reprend avec les rechecks conditionnels et les surfaces restantes, tandis que `raydium_pool_v4` reste un audit conditionnel ultérieur et ne doit pas être promu sans confirmation de program id/rôle/corpus.
|
||||
|
||||
## Organisation documentaire
|
||||
|
||||
@@ -320,7 +320,7 @@ Chaque DEX ou variante de DEX doit avoir sa propre étape de validation. Les fam
|
||||
|
||||
À garder dans la matrice mais sans bloquer les versions immédiates :
|
||||
|
||||
- `raydium_stable_swap` tant que son usage réel n’est pas démontré par corpus local ;
|
||||
- `raydium_stable_swap` est désormais démontré par corpus local en `0.7.52` ; le garder comme DEX effectif supporté, avec surveillance des nouveaux discriminants ;
|
||||
- vieux programmes legacy uniquement utiles pour compatibilité ou replay historique ;
|
||||
- agrégateurs/routeurs comme `okx_dex` tant qu’ils ne correspondent pas à un DEX direct matérialisable ;
|
||||
- entrées ambiguës comme `zora` tant qu’aucun programme Solana pertinent n’est prouvé.
|
||||
@@ -433,7 +433,7 @@ La priorité immédiate après le point de reprise `0.7.43-E5C` est :
|
||||
2. `0.7.49` : `raydium_clmm` — clôturé côté instructions observées, matérialisation non-trade prouvée et nettoyage fallback ;
|
||||
3. `0.7.50-pre-r2` : `raydium_launchpad` clos + re-vérification `raydium_cpmm` / `raydium_clmm` ;
|
||||
4. `0.7.51` : `raydium_amm_v4` ;
|
||||
5. `0.7.52` : `raydium_stable` ;
|
||||
5. `0.7.52` : `raydium_stable_swap` — clôturé ;
|
||||
6. `0.7.53` : `raydium_pool_v4` audit / program-id decision seulement si program id distinct et corpus exploitable ;
|
||||
7. `0.7.54` : `pump_swap` ;
|
||||
8. `0.7.55` : `pump_fun` ;
|
||||
@@ -546,7 +546,7 @@ La suite fonctionnelle reprend par Raydium avant Meteora :
|
||||
2. `0.7.49` — `raydium_clmm` ;
|
||||
3. `0.7.50-pre-r2` — `raydium_launchpad` + clôture CPMM/CLMM ;
|
||||
4. `0.7.51` — `raydium_amm_v4` ;
|
||||
5. `0.7.52` — `raydium_stable` ;
|
||||
5. `0.7.52` — `raydium_stable_swap` — clôturé ;
|
||||
6. `0.7.53` — `raydium_pool_v4` audit conditionnel, sans promotion automatique ;
|
||||
7. `0.7.54+` — Pump, Meteora, Phoenix/OpenBook, Orca puis les autres DEX/surfaces.
|
||||
|
||||
@@ -632,3 +632,36 @@ Cette tranche complète la clôture Raydium en ajoutant `cpi_event` pour CPMM/CL
|
||||
Le discriminant CPMM `40f4bc78a7e9690a` est désormais codé comme `raydium_cpmm.anchor_idl_instruction` : les signatures inspectées correspondent aux instructions Anchor `IdlCreateAccount` / `IdlCloseAccount`, donc il reste `decoded_events_only` et ne matérialise aucune table métier.
|
||||
|
||||
Rapport de clôture : `docs/reports/RAYDIUM_CPMM_CLMM_RECHECK_REPORT_0_7_50_PRE_R2.md`.
|
||||
## Tranche clôturée — 0.7.52 raydium_stable_swap
|
||||
|
||||
`0.7.52` clôture Raydium Stable Swap avec le code local canonique `raydium_stable_swap` et le program id `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`.
|
||||
|
||||
Décisions finales :
|
||||
|
||||
- Stable Swap est décodé en layout legacy **1 octet**.
|
||||
- La surface locale observée `00..0d` est couverte : lifecycle, model setup, admin/config, liquidity, orderbook side effects, fees et swaps.
|
||||
- `swap_base_in` / `swap_base_out` produisent trades/candles uniquement avec des montants exacts dérivés des deltas de vaults (`amountSource=stable_swap_vault_balance_delta`).
|
||||
- Les arguments d’instruction `amountInRaw`, `minimumAmountOutRaw`, `maxAmountInRaw`, `amountOutRaw` sont conservés comme bornes d’instruction, mais ne sont pas utilisés comme prix/montants exacts.
|
||||
- Les transactions failed restent decoded-only avec `skipTradeReason=failed_transaction` et `skipCandleReason=failed_transaction`.
|
||||
|
||||
Livrables de clôture :
|
||||
|
||||
- `kb_lib/src/dex/raydium_stable_swap.rs`
|
||||
- `docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md`
|
||||
- `validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql`
|
||||
|
||||
Validation locale finale :
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 407 passed, 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> ok
|
||||
```
|
||||
|
||||
Replay final observé :
|
||||
|
||||
```text
|
||||
replayed=298, trades=290, liquidity=16, lifecycle=4, candle_upserts=1160,
|
||||
instructionObservations=5317, catalog=40 tokens / 59 pools / 59 pairs
|
||||
```
|
||||
|
||||
Statut : **clôturé côté code et validation locale**.
|
||||
|
||||
66
ROADMAP.md
66
ROADMAP.md
@@ -36,7 +36,7 @@ Règles de planification :
|
||||
| `0.7.49` | `raydium_clmm` | Clôturé : 33 instructions observées/décodées, orderbook CLMM, liquidity/fee/reward/admin/lifecycle, fallbacks upstream nettoyés, 11 Program-data events préparés mais non observés. |
|
||||
| `0.7.50` | `raydium_launchpad` | Bootstrap ouvert : surface LaunchLab/Launchpad, discriminants Carbon/IDL, fallback audit, SQL de validation, aucune matérialisation métier sans corpus. |
|
||||
| `0.7.51` | `raydium_amm_v4` | Clôturé : decoder maximal `00..11`, swaps spécialisés, lifecycle/liquidity/fees/admin/orderbook, `pre_initialize` audit, `simulate_info` decoded-only, cleanup legacy/fallback. |
|
||||
| `0.7.52` | `raydium_stable` | Reprendre Raydium Stable : program ids/IDL, swaps stables, pool lifecycle, liquidity, fees/admin, invariants pricing/candles. |
|
||||
| `0.7.52` | `raydium_stable_swap` | Clôturé : surface legacy `00..0d`, swaps via deltas vault exacts, failed tx decoded-only, invariants trade/candle propres. |
|
||||
| `0.7.53` | `raydium_pool_v4` | Audit / program-id decision seulement : confirmer program id, rôle exact et corpus avant toute promotion métier. |
|
||||
| `0.7.54` | `pump_swap` | Couvrir `buy/sell` et tous les events auxiliaires disponibles : fees, cashback, volume accumulator, admin/config. |
|
||||
| `0.7.55` | `pump_fun` | Traiter launch/bonding/migration ; séparer création token, buy/sell bonding, migration vers DEX effectif. |
|
||||
@@ -855,7 +855,7 @@ Matrice cible initiale :
|
||||
| `raydium_launchpad` | launch surface | planifié, program id local connu | ajouter decoder/materialization dédiée |
|
||||
| `raydium_amm_v4` | AMM legacy | partiel | corpus dédié après autres Raydium |
|
||||
| `raydium_router` | router | partiel | ne pas matérialiser en trade direct avant preuve |
|
||||
| `raydium_stable_swap` | AMM legacy | planifié | traiter seulement si corpus pertinent |
|
||||
| `raydium_stable_swap` | AMM legacy | supporté / 0.7.52 clos | swaps depuis deltas vault exacts ; failed tx decoded-only |
|
||||
| `meteora_dlmm` | DLMM | supporté | verrouiller corpus et non-régression |
|
||||
| `meteora_damm_v1` | AMM legacy | partiel | garder skip explicite sans payload montant/prix |
|
||||
| `meteora_damm_v2` | AMM | partiel | corpus et séparation events |
|
||||
@@ -1006,7 +1006,7 @@ Réalisé :
|
||||
- maintien des launch surfaces comme surfaces reportées et non prioritaires ;
|
||||
- ajout du profil `0.7.39_dex_first_effective_swap_surfaces` ;
|
||||
- validation locale confirmée avec `validationPassed = true`, `blockingIssueCount = 0`, `actionableMissingTradeEventCount = 0` et `missingTradeEventCount = 0` ;
|
||||
- confirmation par corpus local initial que Raydium CLMM est observé, tandis que Raydium AMM v4 et Stable Swap ne sont pas encore exploitables sans constitution de corpus dédiée.
|
||||
- confirmation par corpus local initial que Raydium CLMM est observé ; les tranches ultérieures ont ensuite clôturé Raydium AMM v4 en `0.7.51` et Stable Swap en `0.7.52`.
|
||||
|
||||
Décision : `0.7.39` est clos. La suite immédiate ne doit pas commencer par un décodeur Raydium AMM v4 sans corpus. Il faut d’abord ajouter les outils de découverte on-chain et de backfill ciblé afin d’obtenir des signatures, pools/state accounts, token mints et instructions exploitables.
|
||||
|
||||
@@ -1310,10 +1310,10 @@ Objectif : hisser AMM v4 legacy au niveau de couverture CPMM/CLMM.
|
||||
|
||||
Réalisé : decoder maximal AMM v4 pour tous les discriminants officiels `00..11`, spécialisation des swaps (`swap_base_in`, `swap_base_out`, `swap_base_in_v2`, `swap_base_out_v2`), suppression du legacy `raydium_amm_v4.swap`, observation locale de tous les discriminants, matérialisation validée des familles trade, liquidity, lifecycle, fee, admin/config et orderbook, `pre_initialize` conservé comme lifecycle audit deprecated/partial, `simulate_info` conservé en decoded-only, gaps successful non matérialisés expliqués, et validation des invariants failed/non-swap/single-target.
|
||||
|
||||
### 6.084. Version `0.7.52` — `raydium_stable` event coverage
|
||||
Objectif : reprendre Raydium Stable comme troisième tranche Raydium post-CLMM.
|
||||
### 6.084. Version `0.7.52` — `raydium_stable_swap` event coverage
|
||||
Objectif : reprendre Raydium Stable comme tranche Raydium dédiée après AMM v4.
|
||||
|
||||
À faire : vérifier program ids/IDL, swaps stables, liquidity, pool lifecycle, fees/admin/config, cohérence des montants/prix et absence de faux trades/candles.
|
||||
Réalisé : decoder legacy 1 octet, surface locale `00..0d`, matérialisation lifecycle/liquidity/admin/fee/orderbook selon contexte, swaps `swap_base_in/out` matérialisés uniquement depuis deltas vault exacts (`stable_swap_vault_balance_delta`), transactions failed decoded-only, invariants trade/candle propres.
|
||||
|
||||
### 6.085. Version `0.7.53` — `raydium_pool_v4` audit / program-id decision
|
||||
Objectif : auditer `raydium_pool_v4.json` comme source IDL annexe, sans promotion métier automatique.
|
||||
@@ -1566,7 +1566,7 @@ Ordre de travail recommandé pour la suite :
|
||||
7. `0.7.49` : `raydium_clmm` — clos ;
|
||||
8. `0.7.50-pre-r2` : `raydium_launchpad` clos + re-vérification CPMM/CLMM ;
|
||||
9. `0.7.51` : `raydium_amm_v4` ;
|
||||
10. `0.7.52` : `raydium_stable` ;
|
||||
10. `0.7.52` : `raydium_stable_swap` — clôturé ;
|
||||
11. `0.7.53` : `raydium_pool_v4` audit conditionnel ;
|
||||
12. `0.7.54` : `pump_swap` ;
|
||||
13. `0.7.55` : `pump_fun` ;
|
||||
@@ -1649,7 +1649,7 @@ La tranche CPMM reconnaît désormais tous les discriminants instruction-level l
|
||||
|
||||
`0.7.48` est clôturable côté `raydium_cpmm`. Le decoder couvre les instructions/events CPMM listés par Carbon/fnzero/Raydium CP-Swap, avec matérialisation locale validée pour trades, liquidity, lifecycle, fees et admin/config. `swap_event` reste audit-only pour éviter les doublons avec `swap_base_input` / `swap_base_output`. Les side effects SPL Token / Token-2022 observés via Solscan (`burn`, `transfer`, `transferChecked`, `closeAccount`) restent hors decoder CPMM direct et alimenteront une réflexion transversale future.
|
||||
|
||||
La suite après `0.7.49 raydium_clmm` reprend en `0.7.50-pre-r2` par la clôture Launchpad et la re-vérification CPMM/CLMM, puis `0.7.51 raydium_amm_v4`, `0.7.52 raydium_stable` et `0.7.53 raydium_pool_v4` uniquement comme audit conditionnel, en gardant la même discipline : sources Git/IDL + Solscan pour accélérer la découverte, mais corpus local obligatoire avant toute promotion métier.
|
||||
La suite après `0.7.49 raydium_clmm` reprend en `0.7.50-pre-r2` par la clôture Launchpad et la re-vérification CPMM/CLMM, puis `0.7.51 raydium_amm_v4`, `0.7.52 raydium_stable_swap` et `0.7.53 raydium_pool_v4` uniquement comme audit conditionnel, en gardant la même discipline : sources Git/IDL + Solscan pour accélérer la découverte, mais corpus local obligatoire avant toute promotion métier.
|
||||
|
||||
## Clôture `0.7.51` — Raydium AMM v4
|
||||
|
||||
@@ -1674,4 +1674,52 @@ Décision `raydium_pool_v4` : ne pas ouvrir de decoder autonome dans cette tranc
|
||||
|
||||
Le rapport de décision est `docs/reports/RAYDIUM_POOL_V4_DECISION_NOTE.md`.
|
||||
|
||||
La suite reprend `0.7.52 raydium_stable`, après rechecks CPMM/CLMM/Launchpad si la base de validation les contient.
|
||||
La tranche `0.7.52 raydium_stable_swap` est clôturée ; la suite reprend sur les surfaces restantes ou les audits conditionnels selon le corpus disponible.
|
||||
|
||||
### Addendum final — `0.7.52 raydium_stable_swap`
|
||||
|
||||
Statut : **clôturé**.
|
||||
|
||||
Décision finale : `raydium_stable_swap` est le code local canonique pour le program id `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`. Le decoder utilise un layout legacy 1 octet et couvre la surface localement observée `00..0d`.
|
||||
|
||||
Résultat de tranche :
|
||||
|
||||
- `initialize` matérialise le lifecycle quand le contexte est complet ;
|
||||
- `init_model_data` reste decoded-only expliqué ;
|
||||
- `update_model_data` matérialise `k_sol_pool_admin_events` ;
|
||||
- `deposit` / `withdraw` matérialisent `k_sol_liquidity_events` ;
|
||||
- `monitor_step` / `admin_cancel_orders` matérialisent `k_sol_orderbook_events` quand le contexte est complet ;
|
||||
- `set_params` matérialise `k_sol_pool_admin_events` ;
|
||||
- `withdraw_pnl` / `withdraw_srm` matérialisent `k_sol_fee_events` quand le contexte est complet ;
|
||||
- `simulate_info` reste decoded-only ;
|
||||
- `swap_base_in` / `swap_base_out` matérialisent trades/candles uniquement depuis `amountSource=stable_swap_vault_balance_delta` ;
|
||||
- `stable_swap_instruction_bounds_only` reste decoded-only et ne matérialise pas de trade/candle ;
|
||||
- les transactions failed restent decoded-only avec `failed_transaction`.
|
||||
|
||||
Validation finale :
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 407 passed, 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> ok
|
||||
```
|
||||
|
||||
Replay final observé :
|
||||
|
||||
```text
|
||||
replayed=298, trades=290, liquidity=16, lifecycle=4, candle_upserts=1160,
|
||||
instructionObservations=5317, catalog=40 tokens / 59 pools / 59 pairs
|
||||
```
|
||||
|
||||
Clôture swap spécifique :
|
||||
|
||||
```text
|
||||
swap_base_in stable_swap_vault_balance_delta success 171 decoded / 171 trades
|
||||
swap_base_in stable_swap_instruction_bounds_only failed 27 decoded / 0 trades
|
||||
swap_base_out stable_swap_vault_balance_delta success 4 decoded / 4 trades
|
||||
swap_base_out stable_swap_instruction_bounds_only failed 2 decoded / 0 trades
|
||||
```
|
||||
|
||||
SQL de validation : `validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql`.
|
||||
|
||||
Rapport : `docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md`.
|
||||
|
||||
|
||||
@@ -369,3 +369,16 @@ Règles validées :
|
||||
- les side effects SPL Token / Token-2022 restent transversaux.
|
||||
|
||||
Contrôle final AMM v4 : le SQL `materialized_target_count > 1` doit rester vide.
|
||||
|
||||
## 0.7.52 — Raydium Stable Swap DB model decision
|
||||
|
||||
No schema migration is introduced for `raydium_stable_swap` at tranche opening.
|
||||
|
||||
Stable Swap maps to existing DB targets:
|
||||
|
||||
- `initialize` / `pre_initialize` → `k_sol_pool_lifecycle_events` when pool context is sufficient;
|
||||
- `deposit` / `withdraw` → `k_sol_liquidity_events` when pool/pair context is sufficient;
|
||||
- `swap_base_in` / `swap_base_out` → `k_sol_trade_events` and candles only when mints and amounts are reliable;
|
||||
- `swap_event` → `k_sol_dex_decoded_events` only until a corpus-backed materialization decision exists.
|
||||
|
||||
Side effects from SPL Token, Token-2022, Serum/OpenBook-style accounts or router transport remain transverse evidence and are not promoted as direct `raydium_stable_swap.*` business events without an explicit later DB decision.
|
||||
|
||||
@@ -31,8 +31,8 @@ Cette matrice complète `kb_lib/src/dex_support_matrix.rs`. Elle documente **ce
|
||||
| 1 | `raydium_cpmm` | `supported / 0.7.50-pre-r2 closure recheck` | Couverture CPMM clôturée : swaps, lifecycle, fees, admin/config, deposit/withdraw, `lp_change_event`, `swap_event` decoded-only, `cpi_event` transport Carbon et `anchor_idl_instruction` Solscan/manual pour `40f4bc78a7e9690a`. | Ne pas promouvoir `anchor_idl_instruction` : c'est de la gestion Anchor IDL, pas un événement AMM métier. |
|
||||
| 2 | `raydium_clmm` | `supported / 0.7.50-pre-r2 closure recheck` | Couverture CLMM complétée : `cpi_event`, `update_dynamic_fee_config`, Program-data events locaux, `create_support_mint_associated` vers `k_sol_token_account_events`, familles sans `unknown`, router/swap Program-data en decoded-only. | Rejouer la base CLMM et confirmer que les seuls résidus sont `decoded_events_only`, transactions failed ou absence prouvée de contexte pool/pair. |
|
||||
| 3 | `raydium_launchpad` | `bootstrap / 0.7.50` | Surface canonique normalisée, 1 entrée programme + 26 discriminants Carbon/IDL listés, fallback audit/mapped decoder, SQL dédié. | Créer DB neuve, backfill par discriminant, replay forcé, promouvoir seulement après corpus local. |
|
||||
| 4 | `raydium_amm_v4` | `supported / 0.7.51 closed` | Decoder maximal AMM v4 `00..11`, swaps spécialisés, lifecycle/liquidity/fees/admin/orderbook validés. | Rechecks CPMM/CLMM/Launchpad puis `raydium_stable`. |
|
||||
| 5 | `raydium_stable_swap` | `planned / 0.7.52` | Entrée conservée. | Reprendre Stable séparément : swaps stables, pool lifecycle, liquidity, fees/admin, montants/prix exploitables. |
|
||||
| 4 | `raydium_amm_v4` | `supported / 0.7.51 closed` | Decoder maximal AMM v4 `00..11`, swaps spécialisés, lifecycle/liquidity/fees/admin/orderbook validés. | Stable Swap clôturé ensuite en `0.7.52`; surveiller les surfaces restantes. |
|
||||
| 5 | `raydium_stable_swap` | `supported / 0.7.52 closed` | Decoder legacy 1 octet, surface `00..0d`, swaps matérialisés depuis deltas vault exacts. | Surveiller seulement de nouveaux discriminants ou `swap_event` observé. |
|
||||
| 6 | `raydium_pool_v4` | `to_verify / 0.7.53 conditional audit` | IDL annexe mentionnée par fnzero, non présente dans l'archive locale, pas de program id/rôle confirmé ici. | Ne pas promouvoir tant que program id distinct, rôle exact et corpus exploitable ne sont pas confirmés. |
|
||||
| 7 | `pump_swap` | `supported / 0.7.54 planned` | `buy`/`sell` décodés et matérialisés ; trade/candle OK. | Ajouter tous les events Carbon/Solana Streamer : cashback, fee, volume accumulator, admin/config ; conserver les non-trades hors candles. |
|
||||
| 8 | `pump_fun` | `partial / 0.7.55 launch_surface` | Création/token launch partiellement décodée ; intégrée au pipeline de listings. | Traiter tous les events Pump.fun disponibles : buy/sell/migrate/create/update ; séparer bonding/launch de DEX effectif ; valider migration vers PumpSwap. |
|
||||
@@ -99,7 +99,7 @@ Un event peut devenir `materialized` uniquement si :
|
||||
| `raydium_launchpad` | `launch_surface` | `launch` | `known` | non | oui | non | `bootstrap` | decoded_events_only_until_local_corpus |
|
||||
| `raydium_liquidity_locking` | `to_verify` | `liquidity_locking` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `raydium_router` | `aggregator_router` | `router` | `known` | non | non | non | `partial` | router_not_materialized_as_direct_trade_surface |
|
||||
| `raydium_stable_swap` | `dex_effective` | `AMM` | `known` | non | non | non | `planned` | deprecated_program_not_prioritized |
|
||||
| `raydium_stable_swap` | `dex_effective` | `AMM` | `known` | oui | oui | oui | `supported` | 0.7.52 closed; swaps via `stable_swap_vault_balance_delta` uniquement |
|
||||
| `meteora_dlmm` | `dex_effective` | `DLMM` | `known` | oui | oui | oui | `supported` | |
|
||||
| `meteora_dlc` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | surface_and_program_id_to_verify |
|
||||
| `meteora_damm_v1` | `dex_effective` | `AMM` | `known` | oui | oui | non | `partial` | meteora_damm_v1_swap_without_amount_payload |
|
||||
@@ -266,3 +266,10 @@ La clôture `0.7.50-pre-r2` complète les tranches `0.7.48` et `0.7.49` sans rou
|
||||
|
||||
La tranche a été validée sur base SQLite dédiée : tous les discriminants `00..11` sont observés localement. Les gaps de matérialisation restants sont expliqués par decoded-only, transaction failed ou absence de catalogue/deltas exploitables.
|
||||
|
||||
|
||||
## 0.7.52 — Raydium Stable Swap
|
||||
|
||||
| decoder_code | program id | status | layout | notes |
|
||||
|---|---|---|---|---|
|
||||
| `raydium_stable_swap` | `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h` | supported / closed | legacy 1 octet | Surface locale `00..0d` couverte ; swaps `swap_base_in/out` matérialisés uniquement depuis deltas vault exacts ; instruction bounds et failed tx restent decoded-only. |
|
||||
|
||||
|
||||
@@ -189,3 +189,28 @@ Validation locale finale : tous les discriminants AMM v4 officiels `00..11` sont
|
||||
| `cpi/informational` | `simulate_info` | observed decoded-only | `k_sol_dex_decoded_events_only` | Audit technique uniquement. |
|
||||
| `token side effects` | SPL Token / Token-2022 inner instructions | transversal | decoded-only actuellement | Ne pas promouvoir comme AMM v4 direct. |
|
||||
| `unknown/unmapped audit` | residual `raydium_amm_v4.instruction_audit` | vide | decoded-only si futur inconnu | Tout residual doit être expliqué avant promotion. |
|
||||
|
||||
## 0.7.52 — `raydium_stable_swap`
|
||||
|
||||
Status: **closed on local corpus**.
|
||||
|
||||
| entry | discriminator | family | expected target | local event kind | 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` from vault deltas only | `raydium_stable_swap.swap_base_in` | success/vault-delta materialized; failed decoded-only |
|
||||
| `pre_initialize` | `0a` | `pool_create` | lifecycle or decoded-only | `raydium_stable_swap.pre_initialize` | observed decoded-only / explained in current corpus |
|
||||
| `swap_base_out` | `0b` | `swap` | `k_sol_trade_events` from vault deltas only | `raydium_stable_swap.swap_base_out` | success/vault-delta materialized; failed decoded-only |
|
||||
| `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 locally |
|
||||
|
||||
Stable Swap swaps are not materialized from instruction min/max bounds. `swap_base_in/out` require `amountSource=stable_swap_vault_balance_delta`; `stable_swap_instruction_bounds_only` remains decoded-only and, in the final corpus, appears only on failed transactions.
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@ This file records the manual Solscan account inventory added during the `0.7.50`
|
||||
| `Aldrin AMM V2` | `CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4` | `no_idl` | https://solscan.io/account/CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4 |
|
||||
| `ApePro Smart Wallet Program` | `JSW99DKmxNyREQM14SQLDykeBvEUG63TeohrvmofEiw` | `solscan_program_idl` | https://solscan.io/account/JSW99DKmxNyREQM14SQLDykeBvEUG63TeohrvmofEiw#programIdl |
|
||||
| `Aquifer` | `AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45` | `no_idl` | https://solscan.io/account/AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45 |
|
||||
| `Arbitrage Bot (3s1rA)` | `3s1rAymURnacreXreMy718GfqW6kygQsLNka1xDyW8pC` | `no_idl` | https://solscan.io/account/3s1rAymURnacreXreMy718GfqW6kygQsLNka1xDyW8pC |
|
||||
| `Arbitrage Bot (6MWVT)` | `6MWVTis8rmmk6Vt9zmAJJbmb3VuLpzoQ1aHH4N6wQEGh` | `no_idl` | https://solscan.io/account/6MWVTis8rmmk6Vt9zmAJJbmb3VuLpzoQ1aHH4N6wQEGh |
|
||||
| `Arbitrage Bot (9Zzf9)` | `9Zzf9QqTy3TkyXysvJBsXyuRjda5aXCEJ9vXfL2HKSYv` | `no_idl` | https://solscan.io/account/9Zzf9QqTy3TkyXysvJBsXyuRjda5aXCEJ9vXfL2HKSYv |
|
||||
| `Axiom Trade` | `FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9` | `no_idl` | https://solscan.io/account/FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9 |
|
||||
| `Bags: Token Authority` | `BAGSB9TpGrZxQbEsrEznv5jXXdwyP6AXerN8aVRiAmcv` | `solscan_account` | https://solscan.io/account/BAGSB9TpGrZxQbEsrEznv5jXXdwyP6AXerN8aVRiAmcv |
|
||||
| `Believe : Token Authority` | `5qWya6UjwWnGVhdSBL3hyZ7B45jbk6Byt1hwd7ohEGXE` | `no_idl` | https://solscan.io/account/5qWya6UjwWnGVhdSBL3hyZ7B45jbk6Byt1hwd7ohEGXE |
|
||||
|
||||
67
docs/VALIDATION_STATUS_0_7_52_FINAL.md
Normal file
67
docs/VALIDATION_STATUS_0_7_52_FINAL.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Validation status — 0.7.52 Raydium Stable Swap final
|
||||
|
||||
## Scope
|
||||
|
||||
Decoder: `raydium_stable_swap`
|
||||
|
||||
Program id:
|
||||
|
||||
```text
|
||||
5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
## Final replay snapshot
|
||||
|
||||
```text
|
||||
replayed=298
|
||||
decode_skipped=0
|
||||
ledger_upserts=298
|
||||
unsafe_ledger_rows=258
|
||||
trades=290
|
||||
liquidity=16
|
||||
lifecycle=4
|
||||
tokenAccount=0
|
||||
candle_upserts=1160
|
||||
instructionObservations=5317
|
||||
resetDeleted=1059
|
||||
catalog=40 tokens / 59 pools / 59 pairs
|
||||
```
|
||||
|
||||
## Stable Swap swap closure
|
||||
|
||||
```text
|
||||
raydium_stable_swap.swap_base_in stable_swap_instruction_bounds_only failed decoded=27 trades=0
|
||||
raydium_stable_swap.swap_base_in stable_swap_vault_balance_delta success decoded=171 trades=171
|
||||
raydium_stable_swap.swap_base_out stable_swap_instruction_bounds_only failed decoded=2 trades=0
|
||||
raydium_stable_swap.swap_base_out stable_swap_vault_balance_delta success decoded=4 trades=4
|
||||
```
|
||||
|
||||
No successful Stable Swap swap remains without trade or skip reason.
|
||||
|
||||
## Invariants
|
||||
|
||||
| invariant | status |
|
||||
|---|---|
|
||||
| residual local `instruction_audit` | empty |
|
||||
| residual `upstream_git.instruction_match` for covered entries | empty |
|
||||
| decoded without coverage | empty |
|
||||
| non-swap materialized as trade | empty |
|
||||
| failed tx materialized as trade | empty |
|
||||
| multi-target materialization | empty |
|
||||
| unexplained successful non-materialized event | empty |
|
||||
| successful swap via vault deltas | `trade_count = decoded_count` |
|
||||
| failed swap instruction bounds only | `trade_count = 0` |
|
||||
|
||||
## Decision
|
||||
|
||||
`0.7.52 raydium_stable_swap` is closed for the current local corpus.
|
||||
162
docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md
Normal file
162
docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# 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.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "kb-demo-app",
|
||||
"private": true,
|
||||
"version": "0.7.51",
|
||||
"version": "0.7.52",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "kb-demo-app",
|
||||
"version": "0.7.51",
|
||||
"version": "0.7.52",
|
||||
"identifier": "com.sasedev.kb-demo-app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
@@ -17,6 +17,7 @@ mod raydium_amm_v4;
|
||||
mod raydium_clmm;
|
||||
mod raydium_cpmm;
|
||||
pub(crate) mod raydium_launchpad;
|
||||
mod raydium_stable_swap;
|
||||
|
||||
pub use dexlab::DexlabCreatePoolDecoded;
|
||||
pub use dexlab::DexlabDecodedEvent;
|
||||
@@ -90,3 +91,9 @@ pub use raydium_cpmm::RaydiumCpmmSwapMode;
|
||||
pub use raydium_cpmm::classify_raydium_cpmm_instruction_data;
|
||||
pub use raydium_cpmm::decode_raydium_cpmm_instruction;
|
||||
pub use raydium_cpmm::decode_raydium_cpmm_program_data_event;
|
||||
pub use raydium_stable_swap::RaydiumStableSwapDecodedEvent;
|
||||
pub use raydium_stable_swap::RaydiumStableSwapDecoder;
|
||||
pub use raydium_stable_swap::RaydiumStableSwapInstructionDecoded;
|
||||
pub use raydium_stable_swap::RaydiumStableSwapSwapEventDecoded;
|
||||
pub use raydium_stable_swap::classify_raydium_stable_swap_instruction_data;
|
||||
pub use raydium_stable_swap::decode_raydium_stable_swap_program_data_event;
|
||||
|
||||
1524
kb_lib/src/dex/raydium_stable_swap.rs
Normal file
1524
kb_lib/src/dex/raydium_stable_swap.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ pub struct DexDecodeService {
|
||||
persistence: crate::DetectionPersistenceService,
|
||||
raydium_amm_v4_decoder: crate::RaydiumAmmV4Decoder,
|
||||
raydium_clmm_decoder: crate::RaydiumClmmDecoder,
|
||||
raydium_stable_swap_decoder: crate::RaydiumStableSwapDecoder,
|
||||
pump_fun_decoder: crate::PumpFunDecoder,
|
||||
pump_swap_decoder: crate::PumpSwapDecoder,
|
||||
orca_whirlpools_decoder: crate::OrcaWhirlpoolsDecoder,
|
||||
@@ -33,6 +34,7 @@ impl DexDecodeService {
|
||||
persistence,
|
||||
raydium_amm_v4_decoder: crate::RaydiumAmmV4Decoder::new(),
|
||||
raydium_clmm_decoder: crate::RaydiumClmmDecoder::new(),
|
||||
raydium_stable_swap_decoder: crate::RaydiumStableSwapDecoder::new(),
|
||||
pump_fun_decoder: crate::PumpFunDecoder::new(),
|
||||
pump_swap_decoder: crate::PumpSwapDecoder::new(),
|
||||
orca_whirlpools_decoder: crate::OrcaWhirlpoolsDecoder::new(),
|
||||
@@ -78,6 +80,13 @@ impl DexDecodeService {
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
}
|
||||
let append_result = append_persisted_events_result(
|
||||
&mut persisted,
|
||||
self.decode_and_persist_raydium_stable_swap_events(&transaction, &instructions).await,
|
||||
);
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
}
|
||||
let append_result = append_persisted_events_result(
|
||||
&mut persisted,
|
||||
self.decode_and_persist_raydium_clmm_events(&transaction, &instructions).await,
|
||||
@@ -1512,6 +1521,65 @@ impl DexDecodeService {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn persist_raydium_stable_swap_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
decoded_event: &crate::RaydiumStableSwapDecodedEvent,
|
||||
) -> Result<crate::DexDecodedEventDto, crate::Error> {
|
||||
let transaction_id = match transaction.id {
|
||||
Some(transaction_id) => transaction_id,
|
||||
None => {
|
||||
return Err(crate::Error::InvalidState(format!(
|
||||
"transaction '{}' has no internal id",
|
||||
transaction.signature
|
||||
)));
|
||||
},
|
||||
};
|
||||
let instruction_id = match decoded_event.instruction_id() {
|
||||
Some(instruction_id) => instruction_id,
|
||||
None => {
|
||||
return Err(crate::Error::InvalidState(format!(
|
||||
"raydium stable swap decoded event for transaction '{}' has no instruction id",
|
||||
transaction.signature
|
||||
)));
|
||||
},
|
||||
};
|
||||
let event_kind = decoded_event.event_kind().to_string();
|
||||
let raw_payload_json = match decoded_event.to_payload_json() {
|
||||
Some(payload_json) => payload_json,
|
||||
None => {
|
||||
return Err(crate::Error::Json(
|
||||
"cannot serialize decoded raydium stable swap payload".to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
let payload_value_result = enriched_raydium_payload_value(
|
||||
"raydium_stable_swap",
|
||||
event_kind.as_str(),
|
||||
raw_payload_json.as_str(),
|
||||
);
|
||||
let payload_value = match payload_value_result {
|
||||
Ok(payload_value) => payload_value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
return self
|
||||
.materialize_named_dex_event(
|
||||
transaction,
|
||||
transaction_id,
|
||||
instruction_id,
|
||||
"raydium_stable_swap",
|
||||
crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID.to_string(),
|
||||
event_kind.as_str(),
|
||||
decoded_event.pool_account().map(|value| return value.to_string()),
|
||||
decoded_event.market_account().map(|value| return value.to_string()),
|
||||
decoded_event.base_mint().map(|value| return value.to_string()),
|
||||
decoded_event.quote_mint().map(|value| return value.to_string()),
|
||||
decoded_event.lp_mint().map(|value| return value.to_string()),
|
||||
payload_value,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn persist_pump_fun_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
@@ -1708,6 +1776,32 @@ impl DexDecodeService {
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
async fn decode_and_persist_raydium_stable_swap_events(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
instructions: &[crate::ChainInstructionDto],
|
||||
) -> Result<std::vec::Vec<crate::DexDecodedEventDto>, crate::Error> {
|
||||
let decoded_result = self
|
||||
.raydium_stable_swap_decoder
|
||||
.decode_transaction(transaction, instructions);
|
||||
let decoded_events = match decoded_result {
|
||||
Ok(decoded_events) => decoded_events,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let mut persisted = std::vec::Vec::new();
|
||||
for decoded_event in &decoded_events {
|
||||
let persist_result = self
|
||||
.persist_raydium_stable_swap_event(transaction, decoded_event)
|
||||
.await;
|
||||
let persisted_event = match persist_result {
|
||||
Ok(persisted_event) => persisted_event,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
persisted.push(persisted_event);
|
||||
}
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
async fn decode_and_persist_raydium_clmm_events(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
@@ -2509,6 +2603,13 @@ fn raydium_instruction_audit_spec(
|
||||
candidate_pool_account_index: 3,
|
||||
});
|
||||
}
|
||||
if program_id == crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID {
|
||||
return Some(RaydiumInstructionAuditSpec {
|
||||
protocol_name: "raydium_stable_swap",
|
||||
event_kind: "raydium_stable_swap.instruction_audit",
|
||||
candidate_pool_account_index: 1,
|
||||
});
|
||||
}
|
||||
if program_id == crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID {
|
||||
return Some(RaydiumInstructionAuditSpec {
|
||||
protocol_name: "raydium_launchpad",
|
||||
@@ -4234,6 +4335,7 @@ fn instruction_audit_event_kind_by_protocol(
|
||||
"raydium_amm_v4" => return Some("raydium_amm_v4.instruction_audit"),
|
||||
"raydium_clmm" => return Some("raydium_clmm.instruction_audit"),
|
||||
"raydium_cpmm" => return Some("raydium_cpmm.instruction_audit"),
|
||||
"raydium_stable_swap" => return Some("raydium_stable_swap.instruction_audit"),
|
||||
"raydium_launchpad" => return Some("raydium_launchpad.instruction_audit"),
|
||||
"meteora_dlmm" => return Some("meteora_dlmm.instruction_audit"),
|
||||
"meteora_damm_v1" => return Some("meteora_damm_v1.instruction_audit"),
|
||||
@@ -4719,7 +4821,7 @@ fn raydium_instruction_discriminator_hex(
|
||||
bytes: std::option::Option<&[u8]>,
|
||||
offset: usize,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if protocol_name == "raydium_amm_v4" {
|
||||
if protocol_name == "raydium_amm_v4" || protocol_name == "raydium_stable_swap" {
|
||||
return discriminator_hex_from_bytes_with_len(bytes, offset, 1);
|
||||
}
|
||||
return discriminator_hex_from_bytes(bytes, offset);
|
||||
|
||||
@@ -108,6 +108,12 @@ impl DexDetectService {
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade => {
|
||||
self.detect_raydium_cpmm_trade(&transaction, decoded_event).await
|
||||
},
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapTrade => {
|
||||
self.detect_raydium_stable_swap_trade(&transaction, decoded_event).await
|
||||
},
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapPool => {
|
||||
self.detect_raydium_stable_swap_pool(&transaction, decoded_event).await
|
||||
},
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumClmmTrade => {
|
||||
self.detect_raydium_clmm_trade(&transaction, decoded_event).await
|
||||
},
|
||||
@@ -668,6 +674,78 @@ impl DexDetectService {
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
async fn detect_raydium_stable_swap_pool(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
decoded_event: &crate::DexDecodedEventDto,
|
||||
) -> Result<crate::DexPoolDetectionResult, crate::Error> {
|
||||
return self
|
||||
.detect_materialized_pool_from_decoded_event(
|
||||
transaction,
|
||||
decoded_event,
|
||||
"raydium_stable_swap",
|
||||
crate::PoolKind::Amm,
|
||||
crate::PoolStatus::Active,
|
||||
"signal.dex.raydium_stable_swap",
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn detect_raydium_stable_swap_trade(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
decoded_event: &crate::DexDecodedEventDto,
|
||||
) -> Result<crate::DexPoolDetectionResult, crate::Error> {
|
||||
let dex_id_result =
|
||||
crate::dex_catalog::ensure_known_dex(self.database.as_ref(), "raydium_stable_swap").await;
|
||||
let dex_id = match dex_id_result {
|
||||
Ok(dex_id) => dex_id,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let payload_value_result = parse_payload_json(decoded_event.payload_json.as_str());
|
||||
let payload_value = match payload_value_result {
|
||||
Ok(payload_value) => payload_value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let base_vault_address = extract_payload_string_field(&payload_value, "baseVault");
|
||||
let quote_vault_address = extract_payload_string_field(&payload_value, "quoteVault");
|
||||
let input_result =
|
||||
crate::dex_pool_materialization::DexPoolMaterializationInput::from_decoded_event(
|
||||
decoded_event,
|
||||
dex_id,
|
||||
crate::PoolKind::Amm,
|
||||
crate::PoolStatus::Active,
|
||||
crate::dex_pool_materialization::DexPoolTokenOrder::AlreadyBaseQuote,
|
||||
base_vault_address,
|
||||
quote_vault_address,
|
||||
transaction.source_endpoint_name.clone(),
|
||||
);
|
||||
let input = match input_result {
|
||||
Ok(input) => input,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let detection_result =
|
||||
crate::dex_pool_materialization::materialize_dex_pool(self.database.as_ref(), &input)
|
||||
.await;
|
||||
let detection_result = match detection_result {
|
||||
Ok(detection_result) => detection_result,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let signal_result = self
|
||||
.record_pool_detection_signals(
|
||||
transaction,
|
||||
"signal.dex.raydium_stable_swap",
|
||||
&detection_result,
|
||||
payload_value,
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = signal_result {
|
||||
return Err(error);
|
||||
}
|
||||
return Ok(detection_result);
|
||||
}
|
||||
|
||||
async fn detect_raydium_cpmm_trade(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
|
||||
@@ -11,6 +11,10 @@ pub(crate) enum DexDetectionRoute {
|
||||
RaydiumAmmV4Trade,
|
||||
/// Raydium CPMM trade route.
|
||||
RaydiumCpmmTrade,
|
||||
/// Raydium Stable Swap trade route.
|
||||
RaydiumStableSwapTrade,
|
||||
/// Raydium Stable Swap pool lifecycle route.
|
||||
RaydiumStableSwapPool,
|
||||
/// Raydium CLMM trade route.
|
||||
RaydiumClmmTrade,
|
||||
/// Raydium Launchpad pool or bonding-curve creation route.
|
||||
@@ -67,6 +71,18 @@ pub(crate) fn dex_detection_route(
|
||||
("raydium_cpmm", "raydium_cpmm.swap_base_output") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumCpmmTrade);
|
||||
},
|
||||
("raydium_stable_swap", "raydium_stable_swap.initialize") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapPool);
|
||||
},
|
||||
("raydium_stable_swap", "raydium_stable_swap.pre_initialize") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapPool);
|
||||
},
|
||||
("raydium_stable_swap", "raydium_stable_swap.swap_base_in") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapTrade);
|
||||
},
|
||||
("raydium_stable_swap", "raydium_stable_swap.swap_base_out") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumStableSwapTrade);
|
||||
},
|
||||
("raydium_clmm", "raydium_clmm.swap") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumClmmTrade);
|
||||
},
|
||||
|
||||
@@ -260,6 +260,39 @@ fn infer_expected_db_target_for_entry(
|
||||
);
|
||||
}
|
||||
}
|
||||
if decoder_code == "raydium_stable_swap" {
|
||||
if entry_name == "initialize" || entry_name == "pre_initialize" {
|
||||
return Some(
|
||||
crate::DexEventCoverageEntryDto::DB_TARGET_POOL_LIFECYCLE_EVENTS.to_string(),
|
||||
);
|
||||
}
|
||||
if entry_name == "deposit" || entry_name == "withdraw" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "swap_base_in" || entry_name == "swap_base_out" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_TRADE_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "withdraw_pnl" || entry_name == "withdraw_srm" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_FEE_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "set_params" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_ADMIN_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "monitor_step" || entry_name == "admin_cancel_orders" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_ORDERBOOK_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "update_model_data" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_ADMIN_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "init_model_data"
|
||||
|| entry_name == "simulate_info"
|
||||
|| entry_name == "swap_event"
|
||||
{
|
||||
return Some(
|
||||
crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
if decoder_code == "raydium_clmm" {
|
||||
if entry_name == "initialize_reward" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_REWARD_EVENTS.to_string());
|
||||
@@ -405,6 +438,9 @@ fn infer_event_family_for_entry(
|
||||
if decoder_code == "raydium_cpmm" {
|
||||
return infer_raydium_cpmm_event_family(entry_name, entry_kind);
|
||||
}
|
||||
if decoder_code == "raydium_stable_swap" {
|
||||
return infer_raydium_stable_swap_event_family(entry_name, entry_kind);
|
||||
}
|
||||
return infer_event_family(entry_name, entry_kind);
|
||||
}
|
||||
|
||||
@@ -452,6 +488,34 @@ fn infer_raydium_cpmm_event_family(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn infer_raydium_stable_swap_event_family(
|
||||
entry_name: &str,
|
||||
entry_kind: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if entry_kind == crate::ENTRY_KIND_PROGRAM {
|
||||
return None;
|
||||
}
|
||||
match entry_name {
|
||||
"initialize" => return Some("pool_create".to_string()),
|
||||
"pre_initialize" => return Some("pool_create".to_string()),
|
||||
"init_model_data" => return Some("model_setup".to_string()),
|
||||
"update_model_data" => return Some("admin_config".to_string()),
|
||||
"deposit" => return Some("liquidity_add".to_string()),
|
||||
"withdraw" => return Some("liquidity_remove".to_string()),
|
||||
"monitor_step" => return Some("order_place".to_string()),
|
||||
"set_params" => return Some("admin_config".to_string()),
|
||||
"withdraw_pnl" => return Some("fee".to_string()),
|
||||
"withdraw_srm" => return Some("fee".to_string()),
|
||||
"swap_base_in" => return Some("swap".to_string()),
|
||||
"swap_base_out" => return Some("swap".to_string()),
|
||||
"simulate_info" => return Some("cpi_transport".to_string()),
|
||||
"admin_cancel_orders" => return Some("orderbook_admin".to_string()),
|
||||
"swap_event" => return Some("cpi_transport".to_string()),
|
||||
_ => return infer_event_family(entry_name, entry_kind),
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_raydium_clmm_event_family(
|
||||
entry_name: &str,
|
||||
entry_kind: &str,
|
||||
@@ -725,6 +789,32 @@ fn raydium_amm_v4_local_event_kind(entry_name: &str) -> std::option::Option<std:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn raydium_stable_swap_local_event_kind(
|
||||
entry_name: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
match entry_name {
|
||||
"initialize" => return Some("raydium_stable_swap.initialize".to_string()),
|
||||
"init_model_data" => return Some("raydium_stable_swap.init_model_data".to_string()),
|
||||
"update_model_data" => return Some("raydium_stable_swap.update_model_data".to_string()),
|
||||
"pre_initialize" => return Some("raydium_stable_swap.pre_initialize".to_string()),
|
||||
"deposit" => return Some("raydium_stable_swap.deposit".to_string()),
|
||||
"withdraw" => return Some("raydium_stable_swap.withdraw".to_string()),
|
||||
"monitor_step" => return Some("raydium_stable_swap.monitor_step".to_string()),
|
||||
"set_params" => return Some("raydium_stable_swap.set_params".to_string()),
|
||||
"withdraw_pnl" => return Some("raydium_stable_swap.withdraw_pnl".to_string()),
|
||||
"withdraw_srm" => return Some("raydium_stable_swap.withdraw_srm".to_string()),
|
||||
"swap_base_in" => return Some("raydium_stable_swap.swap_base_in".to_string()),
|
||||
"swap_base_out" => return Some("raydium_stable_swap.swap_base_out".to_string()),
|
||||
"simulate_info" => return Some("raydium_stable_swap.simulate_info".to_string()),
|
||||
"admin_cancel_orders" => {
|
||||
return Some("raydium_stable_swap.admin_cancel_orders".to_string());
|
||||
},
|
||||
"swap_event" => return Some("raydium_stable_swap.swap_event".to_string()),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn known_local_event_kind(
|
||||
decoder_code: &str,
|
||||
entry_name: &str,
|
||||
@@ -732,6 +822,9 @@ pub(crate) fn known_local_event_kind(
|
||||
if decoder_code == "raydium_amm_v4" {
|
||||
return raydium_amm_v4_local_event_kind(entry_name);
|
||||
}
|
||||
if decoder_code == "raydium_stable_swap" {
|
||||
return raydium_stable_swap_local_event_kind(entry_name);
|
||||
}
|
||||
if decoder_code == "raydium_launchpad" && raydium_launchpad_local_entry_is_known(entry_name) {
|
||||
return Some(format!("raydium_launchpad.{}", entry_name));
|
||||
}
|
||||
|
||||
@@ -224,7 +224,29 @@ fn resolve_instruction_name(
|
||||
};
|
||||
return Some(name.to_string());
|
||||
}
|
||||
|
||||
if program_id == crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID
|
||||
|| decoder_code == Some("raydium_stable_swap")
|
||||
{
|
||||
let name = match discriminator_hex {
|
||||
"00" => "raydium_stable_swap.initialize",
|
||||
"01" => "raydium_stable_swap.init_model_data",
|
||||
"02" => "raydium_stable_swap.update_model_data",
|
||||
"03" => "raydium_stable_swap.deposit",
|
||||
"04" => "raydium_stable_swap.withdraw",
|
||||
"05" => "raydium_stable_swap.monitor_step",
|
||||
"06" => "raydium_stable_swap.set_params",
|
||||
"07" => "raydium_stable_swap.withdraw_pnl",
|
||||
"08" => "raydium_stable_swap.withdraw_srm",
|
||||
"09" => "raydium_stable_swap.swap_base_in",
|
||||
"0a" => "raydium_stable_swap.pre_initialize",
|
||||
"0b" => "raydium_stable_swap.swap_base_out",
|
||||
"0c" => "raydium_stable_swap.simulate_info",
|
||||
"0d" => "raydium_stable_swap.admin_cancel_orders",
|
||||
"40c6cde8260871e2" => "raydium_stable_swap.swap_event",
|
||||
_ => return None,
|
||||
};
|
||||
return Some(name.to_string());
|
||||
}
|
||||
if program_id == crate::RAYDIUM_CPMM_PROGRAM_ID || decoder_code == Some("raydium_cpmm") {
|
||||
let name = match discriminator_hex {
|
||||
"9c5420764587467b" => "raydium_cpmm.close_permission_pda",
|
||||
@@ -284,7 +306,6 @@ fn resolve_instruction_name(
|
||||
};
|
||||
return Some(name.to_string());
|
||||
}
|
||||
|
||||
if program_id == crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID
|
||||
|| decoder_code == Some("raydium_launchpad")
|
||||
{
|
||||
@@ -309,7 +330,9 @@ fn discriminator_hex_from_data_json(
|
||||
Some(decoded) => decoded,
|
||||
None => return None,
|
||||
};
|
||||
let discriminator_len = if program_id == crate::RAYDIUM_AMM_V4_PROGRAM_ID {
|
||||
let discriminator_len = if program_id == crate::RAYDIUM_AMM_V4_PROGRAM_ID
|
||||
|| program_id == crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID
|
||||
{
|
||||
1_usize
|
||||
} else {
|
||||
8_usize
|
||||
|
||||
@@ -505,6 +505,8 @@ pub use db::FeeEventEntity;
|
||||
pub use db::InstructionObservationDto;
|
||||
/// Persisted technical observation for one Solana instruction.
|
||||
pub use db::InstructionObservationEntity;
|
||||
/// Raw source row used to rebuild the technical instruction-observation index.
|
||||
pub use db::InstructionObservationSourceRow;
|
||||
/// Application-facing known HTTP endpoint DTO.
|
||||
pub use db::KnownHttpEndpointDto;
|
||||
/// Application-facing known WebSocket endpoint DTO.
|
||||
@@ -517,6 +519,8 @@ pub use db::KnownWsEndpointEntity;
|
||||
pub use db::LaunchAttributionDto;
|
||||
/// Persisted launch attribution row.
|
||||
pub use db::LaunchAttributionEntity;
|
||||
/// Input used to upsert one launch event row.
|
||||
pub use db::LaunchEventUpsertInput;
|
||||
/// Application-facing launch surface DTO.
|
||||
pub use db::LaunchSurfaceDto;
|
||||
/// Persisted launch surface row.
|
||||
@@ -762,12 +766,12 @@ pub use db::query_dex_decoded_events_delete_local_replay_scope_by_transaction_id
|
||||
pub use db::query_dex_decoded_events_delete_locally_covered_upstream_instruction_matches;
|
||||
/// Deletes Meteora DLMM Anchor self-CPI swap audit rows already covered by decoded swaps.
|
||||
pub use db::query_dex_decoded_events_delete_meteora_dlmm_anchor_swap_instruction_audits;
|
||||
/// Deletes decoded DEX instruction audit rows related to one decoded instruction.
|
||||
pub use db::query_dex_decoded_events_delete_related_instruction_audit;
|
||||
/// Deletes one Raydium CLMM instruction-audit row by discriminator.
|
||||
pub use db::query_dex_decoded_events_delete_raydium_clmm_instruction_audit_by_discriminator;
|
||||
/// Deletes one Raydium Launchpad self-CPI audit row by discriminator.
|
||||
pub use db::query_dex_decoded_events_delete_raydium_launchpad_anchor_self_cpi_audit;
|
||||
/// Deletes decoded DEX instruction audit rows related to one decoded instruction.
|
||||
pub use db::query_dex_decoded_events_delete_related_instruction_audit;
|
||||
/// Deletes Raydium CLMM instruction-audit rows for locally mapped CLMM instructions.
|
||||
pub use db::query_dex_decoded_events_delete_replaced_raydium_clmm_instruction_audits;
|
||||
/// Deletes Raydium CPMM instruction-audit rows already covered by local named rows.
|
||||
@@ -778,10 +782,10 @@ pub use db::query_dex_decoded_events_get_by_key;
|
||||
pub use db::query_dex_decoded_events_get_latest_pump_fun_create_payload_by_mint;
|
||||
/// Lists decoded DEX events for one transaction.
|
||||
pub use db::query_dex_decoded_events_list_by_transaction_id;
|
||||
/// Inserts or updates one decoded DEX event row.
|
||||
pub use db::query_dex_decoded_events_upsert;
|
||||
/// Updates the persisted payload of one decoded DEX event row.
|
||||
pub use db::query_dex_decoded_events_update_payload_json_by_id;
|
||||
/// Inserts or updates one decoded DEX event row.
|
||||
pub use db::query_dex_decoded_events_upsert;
|
||||
/// Deletes DEX event coverage entries for one decoder.
|
||||
pub use db::query_dex_event_coverage_entries_delete_by_decoder;
|
||||
/// Lists DEX event coverage entries for one decoder.
|
||||
@@ -819,8 +823,6 @@ pub use db::query_instruction_observations_delete_by_transaction_ids;
|
||||
pub use db::query_instruction_observations_list_by_filter;
|
||||
/// Upserts one instruction observation row.
|
||||
pub use db::query_instruction_observations_upsert;
|
||||
/// Raw source row used to rebuild the technical instruction-observation index.
|
||||
pub use db::InstructionObservationSourceRow;
|
||||
/// Reads one known HTTP endpoint by name.
|
||||
pub use db::query_known_http_endpoints_get;
|
||||
/// Lists all known HTTP endpoints.
|
||||
@@ -841,8 +843,6 @@ pub use db::query_launch_attributions_list_by_pool_id;
|
||||
pub use db::query_launch_attributions_upsert;
|
||||
/// Inserts or updates one launch event row.
|
||||
pub use db::query_launch_events_upsert;
|
||||
/// Input used to upsert one launch event row.
|
||||
pub use db::LaunchEventUpsertInput;
|
||||
/// Returns one launch-surface matching key identified by its kind and value, if it exists.
|
||||
pub use db::query_launch_surface_keys_get_by_match;
|
||||
/// Lists all launch-surface matching keys attached to one launch surface id.
|
||||
@@ -1221,8 +1221,18 @@ pub use dex::RaydiumCpmmSwapDecoded;
|
||||
pub use dex::RaydiumCpmmSwapEventDecoded;
|
||||
/// Raydium CPMM swap mode.
|
||||
pub use dex::RaydiumCpmmSwapMode;
|
||||
/// Raydium Stable Swap decoded event.
|
||||
pub use dex::RaydiumStableSwapDecodedEvent;
|
||||
/// Raydium Stable Swap decoder.
|
||||
pub use dex::RaydiumStableSwapDecoder;
|
||||
/// Decoded Raydium Stable Swap instruction.
|
||||
pub use dex::RaydiumStableSwapInstructionDecoded;
|
||||
/// Decoded Raydium Stable Swap program-data swap event.
|
||||
pub use dex::RaydiumStableSwapSwapEventDecoded;
|
||||
/// Decodes one Raydium CPMM instruction from projected instruction fields.
|
||||
pub use dex::classify_raydium_cpmm_instruction_data;
|
||||
/// Classifies one Raydium Stable Swap instruction data payload.
|
||||
pub use dex::classify_raydium_stable_swap_instruction_data;
|
||||
/// Decodes a Raydium CLMM instruction.
|
||||
pub use dex::decode_raydium_clmm_instruction;
|
||||
/// Decodes one Raydium CLMM Anchor Program data event.
|
||||
@@ -1231,6 +1241,8 @@ pub use dex::decode_raydium_clmm_program_data_event;
|
||||
pub use dex::decode_raydium_cpmm_instruction;
|
||||
/// Decodes Raydium CPMM Anchor events emitted in `Program data:` logs.
|
||||
pub use dex::decode_raydium_cpmm_program_data_event;
|
||||
/// Decodes Raydium Stable Swap `Program data:` event payloads.
|
||||
pub use dex::decode_raydium_stable_swap_program_data_event;
|
||||
/// DEX decode service.
|
||||
pub use dex_decode::DexDecodeService;
|
||||
/// Business-level DEX detection service.
|
||||
|
||||
@@ -98,6 +98,7 @@ pub(crate) async fn resolve_trade_amounts(
|
||||
}
|
||||
if (input.decoded_event.event_kind.starts_with("raydium_amm_v4.")
|
||||
|| input.decoded_event.event_kind.starts_with("raydium_cpmm.")
|
||||
|| input.decoded_event.event_kind.starts_with("raydium_stable_swap.")
|
||||
|| input.decoded_event.event_kind.starts_with("raydium_clmm."))
|
||||
&& (base_amount_raw.is_none()
|
||||
|| quote_amount_raw.is_none()
|
||||
@@ -183,6 +184,21 @@ pub(crate) async fn resolve_trade_amounts(
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if input.decoded_event.event_kind.starts_with("raydium_stable_swap.")
|
||||
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
|
||||
{
|
||||
let resolution_result = crate::trade_amount_resolution::apply_vault_balance_delta_fallback(
|
||||
input,
|
||||
input.base_vault_address,
|
||||
input.quote_vault_address,
|
||||
&mut base_amount_raw,
|
||||
&mut quote_amount_raw,
|
||||
&mut price_quote_per_base,
|
||||
);
|
||||
if let Err(error) = resolution_result {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if input.decoded_event.event_kind.starts_with("raydium_clmm.")
|
||||
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
|
||||
{
|
||||
|
||||
@@ -12836,6 +12836,28 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
|
||||
8,
|
||||
"decoders/raydium-liquidity-locking-decoder/src/instructions/settle_cp_fee_event.rs",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"init_model_data",
|
||||
"01",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#initmodeldata-local-corpus-observed",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"update_model_data",
|
||||
"02",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#updatemodeldata-local-corpus-observed",
|
||||
),
|
||||
upstream_git_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
@@ -12869,6 +12891,50 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
|
||||
1,
|
||||
"decoders/raydium-stable-swap-decoder/src/instructions/pre_initialize.rs",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"monitor_step",
|
||||
"05",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#monitorstep-local-corpus-observed",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"set_params",
|
||||
"06",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#setparams-local-corpus-observed",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"withdraw_pnl",
|
||||
"07",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#withdrawpnl-local-corpus-observed",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"withdraw_srm",
|
||||
"08",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#withdrawsrm-local-corpus-observed",
|
||||
),
|
||||
upstream_git_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
@@ -12902,6 +12968,39 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
|
||||
1,
|
||||
"decoders/raydium-stable-swap-decoder/src/instructions/withdraw.rs",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"simulate_info",
|
||||
"0c",
|
||||
1,
|
||||
"docs.raydium.io/products/stable/instructions#simulateinfo-local-corpus-observed",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"admin_cancel_orders",
|
||||
"0d",
|
||||
1,
|
||||
"raydium-amm/program/src/instruction.rs#admincancelorders-stable-local-corpus-observed",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"raydium_stable_swap",
|
||||
Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
|
||||
"raydium",
|
||||
"stable_swap",
|
||||
crate::ENTRY_KIND_EVENT,
|
||||
"swap_event",
|
||||
"40c6cde8260871e2",
|
||||
8,
|
||||
"docs.raydium.io/products/stable/instructions#program-data-swap-event-decoded-only",
|
||||
),
|
||||
upstream_git_discriminator_entry(
|
||||
"stabble_stable_swap",
|
||||
Some(crate::STABBLE_STABLE_SWAP_PROGRAM_ID),
|
||||
|
||||
292
validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql
Normal file
292
validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql
Normal file
@@ -0,0 +1,292 @@
|
||||
-- file: validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql
|
||||
|
||||
-- 0.7.52 raydium_stable_swap validation checklist.
|
||||
-- Run on a dedicated fresh SQLite database after corpus construction and replay with:
|
||||
-- skipDexDecode=no, forceDexDecode=yes, deferInstructionObservations=yes.
|
||||
|
||||
-- 01. Coverage stable swap.
|
||||
SELECT
|
||||
entry_name,
|
||||
entry_kind,
|
||||
event_family,
|
||||
expected_db_target,
|
||||
proof_status,
|
||||
local_event_kind,
|
||||
discriminator_hex,
|
||||
observed_count,
|
||||
materialized_count,
|
||||
trade_count
|
||||
FROM k_sol_dex_event_coverage_entries
|
||||
WHERE decoder_code = 'raydium_stable_swap'
|
||||
ORDER BY entry_kind, entry_name, discriminator_hex;
|
||||
|
||||
-- 02. Instruction observations.
|
||||
SELECT
|
||||
instruction_name,
|
||||
discriminator_hex,
|
||||
COUNT(*) AS observed_count,
|
||||
COUNT(DISTINCT signature) AS tx_count
|
||||
FROM k_sol_instruction_observations
|
||||
WHERE decoder_code = 'raydium_stable_swap'
|
||||
GROUP BY instruction_name, discriminator_hex
|
||||
ORDER BY observed_count DESC, instruction_name, discriminator_hex;
|
||||
|
||||
-- 03. Residual local instruction audit.
|
||||
SELECT
|
||||
json_extract(payload_json, '$.discriminatorHex') AS discriminator_hex,
|
||||
COUNT(*) AS audit_count,
|
||||
COUNT(DISTINCT transaction_id) AS tx_count
|
||||
FROM k_sol_dex_decoded_events
|
||||
WHERE protocol_name = 'raydium_stable_swap'
|
||||
AND event_kind = 'raydium_stable_swap.instruction_audit'
|
||||
GROUP BY discriminator_hex
|
||||
ORDER BY audit_count DESC, discriminator_hex;
|
||||
|
||||
-- 04. Residual upstream fallback for covered local entries.
|
||||
SELECT
|
||||
json_extract(ug.payload_json, '$.upstreamDecoderCode') AS upstream_decoder_code,
|
||||
json_extract(ug.payload_json, '$.upstreamEntryName') AS entry_name,
|
||||
json_extract(ug.payload_json, '$.upstreamDiscriminatorHex') AS discriminator_hex,
|
||||
json_extract(ug.payload_json, '$.upstreamSourceRepo') AS source_repo,
|
||||
COUNT(*) AS fallback_count,
|
||||
COUNT(DISTINCT ug.transaction_id) AS tx_count
|
||||
FROM k_sol_dex_decoded_events ug
|
||||
JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = json_extract(ug.payload_json, '$.upstreamDecoderCode')
|
||||
AND ce.entry_name = json_extract(ug.payload_json, '$.upstreamEntryName')
|
||||
AND ce.discriminator_hex = json_extract(ug.payload_json, '$.upstreamDiscriminatorHex')
|
||||
AND ce.local_event_kind IS NOT NULL
|
||||
AND ce.local_event_kind <> ''
|
||||
WHERE ug.protocol_name = 'upstream_git'
|
||||
AND ug.event_kind = 'upstream_git.instruction_match'
|
||||
AND json_extract(ug.payload_json, '$.upstreamDecoderCode') = 'raydium_stable_swap'
|
||||
GROUP BY upstream_decoder_code, entry_name, discriminator_hex, source_repo
|
||||
ORDER BY fallback_count DESC, entry_name;
|
||||
|
||||
-- 05. Non-swap safety: non-swap event must not materialize as trade.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
ce.event_family,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(te.id) AS trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = 'raydium_stable_swap'
|
||||
AND ce.local_event_kind = de.event_kind
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
GROUP BY de.event_kind, ce.event_family
|
||||
HAVING ce.event_family <> 'swap'
|
||||
AND COUNT(te.id) > 0
|
||||
ORDER BY trade_count DESC, de.event_kind;
|
||||
|
||||
-- 06. Failed transaction safety: failed tx must not materialize as business trade.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(*) AS decoded_failed_count,
|
||||
COUNT(te.id) AS trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
AND tx.err_json IS NOT NULL
|
||||
AND tx.err_json <> ''
|
||||
AND tx.err_json <> 'null'
|
||||
GROUP BY de.event_kind
|
||||
HAVING COUNT(te.id) > 0
|
||||
ORDER BY trade_count DESC, de.event_kind;
|
||||
|
||||
-- 07. Decoded without coverage entry.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(*) AS decoded_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = 'raydium_stable_swap'
|
||||
AND ce.local_event_kind = de.event_kind
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
AND ce.id IS NULL
|
||||
GROUP BY de.event_kind
|
||||
ORDER BY decoded_count DESC, de.event_kind;
|
||||
|
||||
-- 08. Multi-target materialization.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(DISTINCT de.id) AS decoded_count,
|
||||
COUNT(DISTINCT te.id) AS trade_count,
|
||||
COUNT(DISTINCT le.id) AS liquidity_count,
|
||||
COUNT(DISTINCT pe.id) AS lifecycle_count,
|
||||
COUNT(DISTINCT fe.id) AS fee_count,
|
||||
COUNT(DISTINCT ae.id) AS admin_count,
|
||||
COUNT(DISTINCT oe.id) AS orderbook_count,
|
||||
(
|
||||
CASE WHEN COUNT(DISTINCT te.id) > 0 THEN 1 ELSE 0 END
|
||||
+ CASE WHEN COUNT(DISTINCT le.id) > 0 THEN 1 ELSE 0 END
|
||||
+ CASE WHEN COUNT(DISTINCT pe.id) > 0 THEN 1 ELSE 0 END
|
||||
+ CASE WHEN COUNT(DISTINCT fe.id) > 0 THEN 1 ELSE 0 END
|
||||
+ CASE WHEN COUNT(DISTINCT ae.id) > 0 THEN 1 ELSE 0 END
|
||||
+ CASE WHEN COUNT(DISTINCT oe.id) > 0 THEN 1 ELSE 0 END
|
||||
) AS materialized_target_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_liquidity_events le
|
||||
ON le.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pool_lifecycle_events pe
|
||||
ON pe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_fee_events fe
|
||||
ON fe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pool_admin_events ae
|
||||
ON ae.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_orderbook_events oe
|
||||
ON oe.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
GROUP BY de.event_kind
|
||||
HAVING materialized_target_count > 1
|
||||
ORDER BY materialized_target_count DESC, de.event_kind;
|
||||
|
||||
-- 09. Unexplained successful non-materialized events.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(*) AS unexplained_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_liquidity_events le
|
||||
ON le.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pool_lifecycle_events pe
|
||||
ON pe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_fee_events fe
|
||||
ON fe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pool_admin_events ae
|
||||
ON ae.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_orderbook_events oe
|
||||
ON oe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_token_account_events tae
|
||||
ON tae.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
AND (
|
||||
tx.err_json IS NULL
|
||||
OR tx.err_json = ''
|
||||
OR tx.err_json = 'null'
|
||||
)
|
||||
AND te.id IS NULL
|
||||
AND le.id IS NULL
|
||||
AND pe.id IS NULL
|
||||
AND fe.id IS NULL
|
||||
AND ae.id IS NULL
|
||||
AND oe.id IS NULL
|
||||
AND tae.id IS NULL
|
||||
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipTradeReason')), '') = ''
|
||||
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipLiquidityReason')), '') = ''
|
||||
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipLifecycleReason')), '') = ''
|
||||
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipCatalogReason')), '') = ''
|
||||
GROUP BY de.event_kind
|
||||
ORDER BY unexplained_count DESC, de.event_kind;
|
||||
|
||||
-- 10. Materialization summary.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(DISTINCT de.id) AS decoded_count,
|
||||
COUNT(DISTINCT te.id) AS trade_count,
|
||||
COUNT(DISTINCT le.id) AS liquidity_count,
|
||||
COUNT(DISTINCT pe.id) AS lifecycle_count,
|
||||
COUNT(DISTINCT fe.id) AS fee_count,
|
||||
COUNT(DISTINCT ae.id) AS admin_count,
|
||||
COUNT(DISTINCT oe.id) AS orderbook_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_liquidity_events le
|
||||
ON le.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pool_lifecycle_events pe
|
||||
ON pe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_fee_events fe
|
||||
ON fe.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pool_admin_events ae
|
||||
ON ae.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_orderbook_events oe
|
||||
ON oe.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
GROUP BY de.event_kind
|
||||
ORDER BY de.event_kind;
|
||||
|
||||
|
||||
-- 11. Stable Swap swap amount-source closure.
|
||||
-- Successful swaps must materialize from exact vault deltas.
|
||||
-- Failed swaps may remain instruction-bounds-only and must not materialize as trades.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
json_extract(de.payload_json, '$.amountSource') AS amount_source,
|
||||
CASE
|
||||
WHEN tx.err_json IS NOT NULL
|
||||
AND tx.err_json <> ''
|
||||
AND tx.err_json <> 'null'
|
||||
THEN 'failed'
|
||||
ELSE 'success'
|
||||
END AS tx_status,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(te.id) AS trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
AND de.event_kind IN (
|
||||
'raydium_stable_swap.swap_base_in',
|
||||
'raydium_stable_swap.swap_base_out'
|
||||
)
|
||||
GROUP BY de.event_kind, amount_source, tx_status
|
||||
ORDER BY de.event_kind, amount_source, tx_status;
|
||||
|
||||
-- 12. Stable Swap successful swap without trade and without explanation.
|
||||
-- Expected result: empty.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(*) AS unexplained_success_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
AND de.event_kind IN (
|
||||
'raydium_stable_swap.swap_base_in',
|
||||
'raydium_stable_swap.swap_base_out'
|
||||
)
|
||||
AND (
|
||||
tx.err_json IS NULL
|
||||
OR tx.err_json = ''
|
||||
OR tx.err_json = 'null'
|
||||
)
|
||||
AND te.id IS NULL
|
||||
AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipTradeReason')), '') = ''
|
||||
GROUP BY de.event_kind;
|
||||
|
||||
-- 13. Stable Swap failed swap safety.
|
||||
-- Expected result: empty.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
json_extract(de.payload_json, '$.amountSource') AS amount_source,
|
||||
COUNT(*) AS failed_trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'raydium_stable_swap'
|
||||
AND de.event_kind IN (
|
||||
'raydium_stable_swap.swap_base_in',
|
||||
'raydium_stable_swap.swap_base_out'
|
||||
)
|
||||
AND tx.err_json IS NOT NULL
|
||||
AND tx.err_json <> ''
|
||||
AND tx.err_json <> 'null'
|
||||
GROUP BY de.event_kind, amount_source
|
||||
ORDER BY de.event_kind, amount_source;
|
||||
Reference in New Issue
Block a user