0.7.53
This commit is contained in:
@@ -84,4 +84,5 @@
|
||||
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.
|
||||
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.
|
||||
0.7.53 - Clôture PumpSwap : décodage transaction/log complet, matérialisation `buy/sell/buy_exact_quote_in` depuis sources exactes, events Anchor audit-only, tests synthétiques IDL, validation globale coverage SQL et non-régression Raydium.
|
||||
|
||||
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.7.52"
|
||||
version = "0.7.53"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||
|
||||
87
README.md
87
README.md
@@ -2,6 +2,65 @@
|
||||
|
||||
# khadhroony-bobobot
|
||||
|
||||
## État final validé `0.7.53` — `pump_swap`
|
||||
|
||||
La tranche `0.7.53 pump_swap` est clôturée côté décodage transaction/log et matérialisation métier. Elle ferme le program id unique `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA` sans rouvrir Raydium.
|
||||
|
||||
Points verrouillés :
|
||||
|
||||
- `pump_swap.buy` et `pump_swap.sell` restent matérialisés uniquement depuis montants exacts transaction/vault/balance-delta ;
|
||||
- `pump_swap.buy_exact_quote_in` est matérialisable seulement lorsqu'un `BuyEvent` Anchor exact est présent (`amountSource=pump_swap_anchor_buy_event`) ; les cas `instruction_bounds_only` restent decoded-only avec raison explicite ;
|
||||
- les events Anchor `*_event` sont décodés comme events autonomes audit-only, sauf exception explicitement matérialisable (`claim_token_incentives_event` si un corpus réussi apparaît) ;
|
||||
- les transactions failed restent traçables mais non actionnables ;
|
||||
- les non-trades PumpSwap alimentent uniquement les tables métier prévues (`liquidity`, `lifecycle`, `fee`, `reward`, `admin`) et ne créent jamais de trade/candle ;
|
||||
- les tests synthétiques verrouillent les instructions/events IDL non observés dans le corpus local ;
|
||||
- la surveillance globale distingue maintenant les vrais gaps locaux, le backlog `upstream_git` et les observations non attribuées.
|
||||
|
||||
Validation locale finale rapportée :
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 421 passed / 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
```
|
||||
|
||||
Dernier replay élargi rapporté après backfill pool :
|
||||
|
||||
```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 de fermeture :
|
||||
|
||||
- `pump_swap` decoded without coverage : vide ;
|
||||
- fallback `upstream_git` PumpSwap couvert localement : vide ;
|
||||
- successful trade candidates PumpSwap sans trade et sans raison explicite : vide ;
|
||||
- failed transaction avec business trade : vide ;
|
||||
- non-swap matérialisé en trade : vide ;
|
||||
- multi-target materialization : vide ;
|
||||
- Raydium AMM v4 / CLMM / CPMM targeted observation gaps : vide après normalisation.
|
||||
|
||||
Livrables `0.7.53` :
|
||||
|
||||
- `docs/reports/PUMP_SWAP_EVENT_COVERAGE_REPORT.md` ;
|
||||
- `docs/reports/DEX_COVERAGE_GLOBAL_WATCHLIST_0_7_53.md` ;
|
||||
- `validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql` ;
|
||||
- `validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql` ;
|
||||
- `idls/` comme corpus local d'IDL Solscan à comparer aux sources Git.
|
||||
|
||||
La suite immédiate est `pump_fees` / `pump_fun` selon priorité de backlog observé. Les petits gaps Meteora sont volontairement reportés aux tranches Meteora futures.
|
||||
|
||||
|
||||
## État final validé `0.7.51` — `raydium_amm_v4`
|
||||
|
||||
La tranche `0.7.51 raydium_amm_v4` est clôturable côté `kb_lib` après validation locale du decoder maximal AMM v4.
|
||||
@@ -118,9 +177,10 @@ Sources prioritaires :
|
||||
|
||||
| Source | Usage attendu |
|
||||
|---|---|
|
||||
| `idls/` | Corpus local d’IDL téléchargés depuis Solscan ; source de savoir locale à comparer aux sources Git avant promotion métier. |
|
||||
| `https://github.com/sevenlabs-hq/carbon/tree/main/decoders` | Source principale de discriminants, instructions et events multi-protocoles. |
|
||||
| `https://github.com/0xfnzero/solana-streamer` | Source complémentaire pour PumpFun, PumpSwap, Bonk et Raydium CPMM. |
|
||||
| `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl` | IDL complémentaires pour programmes Solana supportés par parser SDK. |
|
||||
| `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idls` | IDL complémentaires pour programmes Solana supportés par parser SDK. |
|
||||
| `https://github.com/pinax-network/substreams-solana-idls/tree/main/src` | IDL et layouts additionnels à comparer au registre local. |
|
||||
| `https://github.com/hodlwarden/solana-tx-parser/tree/main/src` | Décodage transactionnel complémentaire et conventions de mapping. |
|
||||
| `https://github.com/openbook-dex/openbook-v2` | Source officielle OpenBook v2 : programme, IDL et logs. |
|
||||
@@ -427,17 +487,14 @@ Si une requête DB est ajoutée ou modifiée, mettre à jour les re-exports dans
|
||||
|
||||
## 8. Priorité immédiate
|
||||
|
||||
La priorité immédiate après le point de reprise `0.7.43-E5C` est :
|
||||
La priorité immédiate après la clôture `0.7.53` est la suivante :
|
||||
|
||||
1. `0.7.48` : `raydium_cpmm` — clôturé côté event coverage ;
|
||||
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_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` ;
|
||||
9. `0.7.56+` : Meteora, Phoenix/OpenBook, Orca puis validation progressive des autres DEX/surfaces issus du registre upstream Git.
|
||||
1. `0.7.53` est clos pour `pump_swap` : ne rouvrir que pour correction de bug, pas pour ajout fonctionnel IDL déjà couvert ;
|
||||
2. maintenir les checks globaux de surveillance dans `validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql` après chaque gros backfill ;
|
||||
3. traiter ensuite le backlog observé, en priorité `pump_fees`, puis `pump_fun`, puis `jupiter_swap` si l’objectif devient l’analyse des routes/agrégateurs ;
|
||||
4. reporter volontairement les corrections Meteora restantes (`meteora_dlmm.swap`, `meteora_damm_v2.swap`, `meteora_damm_v2.instruction_audit`) aux tranches Meteora dédiées ;
|
||||
5. ne pas rouvrir `raydium_amm_v4`, `raydium_clmm` ou `raydium_cpmm` tant que les requêtes Raydium normalisées restent vides ;
|
||||
6. garder `raydium_launchpad` et `raydium_stable_swap` en surveillance : les entrées non observées restent `upstream_git_mapped_unverified`, pas des régressions.
|
||||
|
||||
Garde-fous constants :
|
||||
|
||||
@@ -547,8 +604,12 @@ La suite fonctionnelle reprend par Raydium avant Meteora :
|
||||
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_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.
|
||||
6. `0.7.53` — `pump_swap` — clôturé ;
|
||||
7. `0.7.54` — `pump_fees` ;
|
||||
8. `0.7.55` — `pump_fun` ;
|
||||
9. `0.7.56+` — Meteora, routers/agrégateurs, Phoenix/OpenBook, Orca puis les autres DEX/surfaces.
|
||||
|
||||
`raydium_pool_v4.json` reste repoussé en audit conditionnel tardif, pas une tranche bloquante.
|
||||
|
||||
## Note 0.7.48 — Raydium CPMM event coverage
|
||||
|
||||
|
||||
321
ROADMAP.md
321
ROADMAP.md
@@ -2,6 +2,30 @@
|
||||
|
||||
# khadhroony-bobobot — Roadmap
|
||||
|
||||
## État courant — clôture `0.7.53 pump_swap`
|
||||
|
||||
`0.7.53` est clos pour `pump_swap`. La version ferme le décodage transaction/log de PumpSwap, la matérialisation `buy`, `sell` et `buy_exact_quote_in` depuis sources exactes, les events Anchor audit-only, les tests synthétiques IDL, et la surveillance SQL globale. Les futures interventions PumpSwap doivent être des corrections de bugs ou des adaptations à un changement externe prouvé, pas l’ajout d’entrées IDL déjà connues.
|
||||
|
||||
Décisions de clôture :
|
||||
|
||||
- `pump_swap.buy_exact_quote_in` est matérialisé uniquement avec `amountSource=pump_swap_anchor_buy_event`; les rows `instruction_bounds_only` restent decoded-only ;
|
||||
- les events Anchor `buy_event`, `sell_event`, `deposit_event`, `withdraw_event`, `create_pool_event`, etc. restent audit-only pour éviter le double-count avec les instructions locales ;
|
||||
- `claim_token_incentives_event` est testé et prêt à matérialiser `reward` si un corpus réussi apparaît ; les signatures observées côté instruction étaient failed et ne doivent pas produire de reward ;
|
||||
- `sync_user_volume_accumulator_event` reste `implemented_idl_unobserved` : plus de 60/70 signatures supplémentaires ont confirmé l’instruction sans faire apparaître l’event ;
|
||||
- Raydium AMM v4 / CLMM / CPMM ne présentent plus de gap ciblé après normalisation des observations ;
|
||||
- les gaps Meteora sont explicitement différés.
|
||||
|
||||
### Phasage immédiat après `0.7.53`
|
||||
|
||||
| Priorité | Tranche | Surface | Raison |
|
||||
|---:|---|---|---|
|
||||
| 1 | `0.7.54` | `pump_fees` | Backlog observé dominant (`get_fees` très fréquent) ; aucun trade/candle direct attendu. |
|
||||
| 2 | `0.7.55` | `pump_fun` | Launch/bonding/migration et creator fees observés en fallback upstream. |
|
||||
| 3 | `0.7.56+` | `meteora_*` | Corriger les gaps locaux Meteora reportés volontairement. |
|
||||
| 4 | ultérieur | `jupiter_swap` / agrégateurs | Routes et comptes auxiliaires à traiter sans double-count des DEX effectifs. |
|
||||
|
||||
|
||||
|
||||
## 0.7.47-1FE5 — Décision de planification : ne plus viser “tous les events en une session”
|
||||
|
||||
La phase `0.7.47` a montré que l’objectif “réimplémenter tous les décodeurs Carbon et toutes les sources en un seul bloc” est trop large. Le plan est donc redécoupé en **un DEX/version par tranche**, avec une matrice documentaire dédiée : `docs/DEX_DECODER_MATRIX.md`.
|
||||
@@ -19,37 +43,111 @@ Règles de planification :
|
||||
|
||||
| Source | Usage |
|
||||
|---|---|
|
||||
| `idls/` | Corpus local d’IDL Solscan téléchargés et versionnés dans le workspace ; source locale obligatoire à comparer aux liens Git avant décision de decoder. |
|
||||
| `https://github.com/sevenlabs-hq/carbon/tree/main/decoders` | Source principale des decoders multi-protocoles. |
|
||||
| `https://github.com/0xfnzero/solana-streamer` | Source complémentaire PumpFun/PumpSwap/Bonk/Raydium CPMM. |
|
||||
| `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl` | IDL complémentaires. |
|
||||
| `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idls` | IDL complémentaires. |
|
||||
| `https://github.com/pinax-network/substreams-solana-idls/tree/main/src` | IDL et layouts additionnels. |
|
||||
| `https://github.com/hodlwarden/solana-tx-parser/tree/main/src` | Parsers transactionnels complémentaires. |
|
||||
| `https://github.com/openbook-dex/openbook-v2` | Source officielle OpenBook v2. |
|
||||
| `https://github.com/all-in-one-blockchain/phoenix-onchain-mm` | Source Phoenix/MM complémentaire. |
|
||||
| `https://docs.vybenetwork.com/docs/available-dexs-amms` | Source externe de découverte DEX/AMM, non vérifiante. |
|
||||
|
||||
### Plan révisé `0.7.48` à `0.7.63+`
|
||||
### Plan révisé `0.7.53+` — une version par `program_id`
|
||||
|
||||
| Version cible | Scope | Objectif de clôture |
|
||||
|---|---|---|
|
||||
| `0.7.48` | `raydium_cpmm` | Clôturé : instructions/events CPMM, lifecycle, fees, admin/config, deposit/withdraw, `lp_change_event`, invariants trade/candle. |
|
||||
| `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_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. |
|
||||
| `0.7.56` | `meteora_dbc` | Couverture DBC : bonding curve, swap, migration, launch attribution, fees/admin, non-trade. |
|
||||
| `0.7.57` | `meteora_dlmm` | Audit final de parité avec sources Git/IDL ; fermer ou documenter les audits résiduels. |
|
||||
| `0.7.58` | `meteora_damm_v1` | Parité upstream complète ; résoudre les cas non matérialisés faute de pool/pair quand possible. |
|
||||
| `0.7.59` | `meteora_damm_v2` | Couverture DAMM v2 complète : create, swap, liquidity, fees/admin/config ; décider trade actionability. |
|
||||
| `0.7.60` | `phoenix_v1` | Finir tous les events Git disponibles en audit ; préparer mais ne pas activer trade materialization. |
|
||||
| `0.7.61` | `openbook_v2` | Finir layouts logs/events ; définir conditions futures de trade/candle sans les activer par défaut. |
|
||||
| `0.7.62` | `orca_whirlpools` | Reprendre Whirlpools depuis IDL/source : swaps, pools, positions, liquidity, fees/rewards. |
|
||||
| `0.7.63+` | Launch surfaces / DEX candidats / validation consolidée | Moonshot/Moonit, Boop, Heaven, Bags, LetsBonk, FluxBeam, DexLab, Lifinity, Stabble, BonkSwap, GooseFX, Obric, SolFi puis base neuve multi-DEX. |
|
||||
Règle de planification validée après `0.7.52` : **une version cible = un `program_id`**.
|
||||
|
||||
Ce plan remplace les anciens regroupements larges `0.7.50+` qui mélangeaient plusieurs DEX dans une même version.
|
||||
Exceptions : les comptes non-programmes (`platform_config`, token authority, comptes de configuration, comptes de pool, accounts de programme) ne créent pas de version decoder autonome. Ils restent des sources de contexte ou d’enrichissement. `SOLSCAN_ACCOUNT_SOURCES` reste un inventaire de découverte, pas une preuve de support local.
|
||||
|
||||
| Version cible | Decoder / surface | Program id | Famille | Objectif de clôture |
|
||||
|---|---|---|---|---|
|
||||
| `0.7.53` | `pump_swap` | `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA` | Pump / AMM | **Clos** : `buy/sell/buy_exact_quote_in` matérialisés seulement depuis sources exactes ; events Anchor audit-only ; tests synthétiques IDL ; SQL global. |
|
||||
| `0.7.54` | `pump_fees` | `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` | Pump / fee | Couvrir fee accounting/claim/config observés ; aucun trade/candle direct. |
|
||||
| `0.7.55` | `pump_fun` | `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` | Pump / launch-bonding | Couvrir create, buy/sell bonding, migration/graduate, config/update ; séparer bonding curve et DEX effectif. |
|
||||
| `0.7.56` | `meteora_dbc` | `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` | Meteora / DBC | Compléter launch/bonding, swaps exploitables, migration, fees/admin/config. |
|
||||
| `0.7.57` | `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | Meteora / DLMM | Parité upstream finale : swaps, bins, positions, liquidity, fees/rewards/admin. |
|
||||
| `0.7.58` | `meteora_damm_v1` | `Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB` | Meteora / DAMM v1 | Parité upstream finale : pools, swaps, liquidity, lock, fees/admin. |
|
||||
| `0.7.59` | `meteora_damm_v2` | `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` | Meteora / DAMM v2 | Couverture complète : create/custom pools, swaps, liquidity, dynamic config, fees/admin. |
|
||||
| `0.7.60` | `meteora_vault` | `24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi` | Meteora / vault | Vault deposit/withdraw/fee/accounting ; pas de candle directe. |
|
||||
| `0.7.61` | `system_program` | `11111111111111111111111111111111` | Système Solana | Create/assign/transfer account ; side effects de contexte, pas de trade. |
|
||||
| `0.7.62` | `spl_token` | `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` | SPL Token | Transfer, mint, burn, close account, sync native ; base transversale pour deltas. |
|
||||
| `0.7.63` | `spl_token_2022` | `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` | Token-2022 | Transfers/extensions Token-2022, mint/burn/close, comptes et side effects. |
|
||||
| `0.7.64` | `associated_token_account` | `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL` | Système token | Création ATA, rattachement wallet/token/pool. |
|
||||
| `0.7.65` | `compute_budget` | `ComputeBudget111111111111111111111111111111` | Contexte tx | Budget/prioritization fee ; utile scoring/MEV, pas de trade. |
|
||||
| `0.7.66` | `memo` | `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr` | Contexte tx | Mémo transactionnel et attribution éventuelle. |
|
||||
| `0.7.67` | `address_lookup_table` | `AddressLookupTab1e1111111111111111111111111` | Contexte tx | Résolution/diagnostic ALT si nécessaire. |
|
||||
| `0.7.68` | `mpl_token_metadata` | `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s` | Metadata | Enrichissement token/NFT/mint metadata. |
|
||||
| `0.7.69` | `mpl_core` | `CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d` | Metadata / asset | Contexte asset si présent dans corpus. |
|
||||
| `0.7.70` | `bubblegum` | `BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY` | Compressed assets | Audit/contexte assets compressés, pas DEX. |
|
||||
| `0.7.71` | `raydium_routing` | `routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS` | Router | Route/legs Raydium ; éviter le double-count avec DEX effectifs. |
|
||||
| `0.7.72` | `jupiter_swap_v6` | `JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4` | Aggregator | Route attribution, legs, no duplicate trade/candle. |
|
||||
| `0.7.73` | `jupiter_swap_v4` | `JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB` | Legacy aggregator | Audit/route only si corpus encore utile. |
|
||||
| `0.7.74` | `dflow_aggregator_v4` | `DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH` | Aggregator | Route/intent/orderflow ; pas de double matérialisation. |
|
||||
| `0.7.75` | `okx_dex` | `6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma` | Aggregator/router | Route attribution ; trades seulement si source exacte non doublonnée. |
|
||||
| `0.7.76` | `onchain_labs_dex_v2` | `proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u` | Router/DEX candidat | Corpus d’abord ; classifier route vs DEX effectif. |
|
||||
| `0.7.77` | `titan_router` | `T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT` | Router | Audit route-only sauf preuve de trade direct non doublonné. |
|
||||
| `0.7.78` | `sanctum_router` | `stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq` | Router | Route/liquid staking context ; pas de candle DEX directe. |
|
||||
| `0.7.79` | `orca_whirlpools` | `whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc` | DEX avec IDL/source | Swaps, pools, positions, liquidity, fees/rewards. |
|
||||
| `0.7.80` | `stabble_stable_swap` | `swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ` | DEX avec IDL/source | Stable swap ; deltas exacts, liquidity/admin. |
|
||||
| `0.7.81` | `stabble_weighted_swap` | `swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW` | DEX avec IDL/source | Weighted swap, deltas exacts, liquidity/admin. |
|
||||
| `0.7.82` | `stabble_clmm` | `6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6` | DEX avec IDL/source | CLMM Stabble si corpus utile. |
|
||||
| `0.7.83` | `bonkswap` | `BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p` | DEX avec IDL/source | Swap/liquidity/non-trade. |
|
||||
| `0.7.84` | `boop_fun` | `boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4` | Launch/DEX candidat | Launch/swap/migration selon corpus. |
|
||||
| `0.7.85` | `byreal_clmm` | `REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2` | DEX avec IDL/source | CLMM ; corpus puis matérialisation contrôlée. |
|
||||
| `0.7.86` | `fusionamm` | `fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9` | DEX avec IDL/source | AMM ; swaps/liquidity si corpus. |
|
||||
| `0.7.87` | `goosefx_v1` | `GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT` | DEX avec IDL/source | DEX/AMM selon corpus. |
|
||||
| `0.7.88` | `goosefx_v2` | `GFXsSL5sSaDfNFQUYsHekbWBW1TsFdjDYzACh62tEHxn` | DEX avec IDL/source | DEX/AMM selon corpus. |
|
||||
| `0.7.89` | `guac_swap` | `Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1` | DEX avec IDL/source | Swap/liquidity si corpus. |
|
||||
| `0.7.90` | `hylo_exchange` | `HYEXCHtHkBagdStcJCp3xbbb9B7sdMdWXFNj6mdsG4hn` | DEX/source à classifier | Classer DEX/lending/stable selon IDL/corpus. |
|
||||
| `0.7.91` | `printr` | `T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint` | Launch/DEX candidat | Corpus d’abord ; surface launch/swap à confirmer. |
|
||||
| `0.7.92` | `moonit` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Launch/DEX candidat | Launch/migration/swap si prouvé. |
|
||||
| `0.7.93` | `metadao_amm_v0_5` | `AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ` | DEX avec source | AMM futarchy ; corpus et price semantics. |
|
||||
| `0.7.94` | `metadao_bid_wall` | `WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx` | Order/bid-wall | Order/bid-wall context ; pas de candle directe sans fill exact. |
|
||||
| `0.7.95` | `metadao_launchpad` | `moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM` | Launch surface | Launch/ICO surface ; pas DEX effectif par défaut. |
|
||||
| `0.7.96` | `vertigo` | `vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ` | DEX/source | Swap/launch selon corpus. |
|
||||
| `0.7.97` | `virtuals` | `5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki` | Launch/DEX candidat | Launch/AMM à confirmer. |
|
||||
| `0.7.98` | `wavebreak` | `waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF` | DEX/source | Corpus et rôle exact. |
|
||||
| `0.7.99` | `woofi` | `WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb` | DEX/router | Swap/route selon corpus. |
|
||||
| `0.7.100` | `pancake_swap` | `HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq` | DEX/source | DEX Solana à confirmer par corpus. |
|
||||
| `0.7.101` | `gavel` | `srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi` | Source upstream | Corpus d’abord ; rôle exact à classer. |
|
||||
| `0.7.102` | `heaven` | `HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o` | Launch/DEX candidat | Launch/DEX selon corpus. |
|
||||
| `0.7.103` | `lifinity_v2` | `2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c` | DEX legacy/actif | Support selon corpus. |
|
||||
| `0.7.104` | `moonshot` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Source upstream/Solscan | À dédupliquer avec `moonit` si même program id. |
|
||||
| `0.7.105` | `openbook_v2` | `opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb` | Orderbook | Audit/orderbook complet ; trade/candle seulement si fills exacts. |
|
||||
| `0.7.106` | `phoenix_v1` | `PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY` | Orderbook | Audit-only complet avant toute matérialisation fill. |
|
||||
| `0.7.107` | `alphaq` | `ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA` | Solscan/no IDL | Probe par Demo3 + corpus ; décider support ou abandon. |
|
||||
| `0.7.108` | `aquifer` | `AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45` | Solscan/no IDL | Probe uniquement. |
|
||||
| `0.7.109` | `bisonfi` | `BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi` | Solscan/no IDL | Probe uniquement. |
|
||||
| `0.7.110` | `dexlab` | `DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N` | Solscan/no IDL | Vérifier support partiel / corpus. |
|
||||
| `0.7.111` | `fluxbeam` | `FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X` | Solscan/no IDL | Vérifier support partiel / corpus. |
|
||||
| `0.7.112` | `goonfi` | `goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j` | Solscan/no IDL | Probe. |
|
||||
| `0.7.113` | `goonfi_v2` | `goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE` | Solscan/no IDL | Probe ; adresse à revérifier si erreur de taille. |
|
||||
| `0.7.114` | `humidifi` | `9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp` | Solscan/no IDL | Probe. |
|
||||
| `0.7.115` | `obric_v2` | `obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y` | Solscan/no IDL | Probe. |
|
||||
| `0.7.116` | `ondo_global_market` | `XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm` | Solscan IDL | Rôle marché/tokenized assets à confirmer. |
|
||||
| `0.7.117` | `scorch` | `SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn` | Solscan/no IDL | Probe. |
|
||||
| `0.7.118` | `solfi` | `SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe` | Solscan/no IDL | Probe. |
|
||||
| `0.7.119` | `solfi_v2` | `SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF` | Solscan/no IDL | Probe. |
|
||||
| `0.7.120` | `zerofi` | `ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY` | Solscan/no IDL | Probe. |
|
||||
| `0.7.121` | `zora` | `zoRabwLGd5zXaV7Gxacppw8tcceXEiTrSKyNLSaSTUc` | Solscan/no IDL | Probe, pas de promotion sans corpus. |
|
||||
| `0.7.122` | `1dex` | `DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm` | Solscan/no IDL | Probe. |
|
||||
| `0.7.123` | `aldrin_amm` | `AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.124` | `aldrin_amm_v2` | `CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.125` | `crema_finance` | `CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.126` | `cropper_finance` | `CTMAxxk34HjKWxQ3QLZK1HpaLXmBveao3ESePXbiyfzh` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.127` | `cropper_whirlpool` | `H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.128` | `mercurial_stable_swap` | `MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky` | Legacy/no IDL | Historique stable swap ; deltas exacts si support. |
|
||||
| `0.7.129` | `saber_stable_swap` | `SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ` | Legacy/no IDL | Historique stable swap. |
|
||||
| `0.7.130` | `saros_amm` | `SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.131` | `step_finance_swap` | `SSwpMgqNDsyV7mAgN9ady4bDVu5ySjmmXejXvy2vLt1` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.132` | `stepn_dooar_swap` | `Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.133` | `raydium_amm_v2_legacy` | `RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr` | Raydium legacy/no IDL | Historique Raydium ; corpus d’abord. |
|
||||
| `0.7.134` | `raydium_amm_v3_legacy` | `27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv` | Raydium legacy/no IDL | Historique Raydium ; ne pas confondre avec CLMM moderne. |
|
||||
| `0.7.135` | `raydium_pool_v4_json_audit` | aucun `program_id` prouvé par le fichier seul | Audit source annexe | Vérifier `sol-parser-sdk/idls/raydium_pool_v4.json` après les surfaces documentées ; patch AMM v4 si amélioration, sinon clôture no-op. |
|
||||
| `0.7.136` | cleanup `SOLSCAN_ACCOUNT_SOURCES` | n/a | Nettoyage registry/constants | Retirer doublons/promotions ; les programmes validés deviennent constantes/support matrix, les comptes non-programmes restent contexte ou sont supprimés. |
|
||||
| `0.7.137` | base neuve multi-programmes | n/a | Validation consolidée | Replay consolidé, coverage global, zéro faux trade/candle, diagnostics bloquants à zéro. |
|
||||
|
||||
Ce plan remplace les regroupements larges qui mélangeaient plusieurs DEX ou plusieurs `program_id` dans une seule tranche. `raydium_pool_v4.json` est explicitement repoussé vers la fin : il ne bloque plus `0.7.53`.
|
||||
|
||||
|
||||
|
||||
@@ -1315,60 +1413,132 @@ Objectif : reprendre Raydium Stable comme tranche Raydium dédiée après AMM v4
|
||||
|
||||
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.
|
||||
### 6.085. Versions `0.7.53` à `0.7.137` — phasage par `program_id`
|
||||
Objectif : reprendre la suite après `0.7.52 raydium_stable_swap` avec une règle stricte : **une version = un `program_id`**.
|
||||
|
||||
À faire : confirmer s'il correspond à un program id distinct, confirmer son rôle exact par rapport à `raydium_amm_v4`, chercher un corpus exploitable, puis décider seulement ensuite si une surface dédiée est nécessaire.
|
||||
Les comptes non-programmes ne créent pas de tranche decoder autonome. `SOLSCAN_ACCOUNT_SOURCES` reste un inventaire de découverte et sera nettoyé après validation des surfaces.
|
||||
|
||||
### 6.086. Version `0.7.54` — `pump_swap` event coverage
|
||||
Objectif : compléter `pump_swap` au-delà de `buy/sell`.
|
||||
#### Bloc Pump
|
||||
|
||||
À faire : couvrir fees, cashback, volume accumulator, admin/config et autres events upstream disponibles, tout en maintenant l’invariant non-trade = zéro trade/candle.
|
||||
| Version | Decoder / surface | Program id | Objectif |
|
||||
|---:|---|---|---|
|
||||
| `0.7.53` | `pump_swap` | `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA` | Clos : `buy/sell/buy_exact_quote_in` depuis sources exactes, non-trades spécialisés, events Anchor audit-only. |
|
||||
| `0.7.54` | `pump_fees` | `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` | Couvrir fee accounting/claim/config ; aucun trade/candle direct. |
|
||||
| `0.7.55` | `pump_fun` | `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` | Couvrir launch/bonding/migration : create, buy/sell bonding, update/config, graduate/migrate. |
|
||||
|
||||
### 6.087. Version `0.7.55` — `pump_fun` launch/bonding/migration
|
||||
Objectif : séparer launch/bonding de DEX effectif et valider migration vers PumpSwap ou autre surface tradable.
|
||||
#### Bloc Meteora
|
||||
|
||||
À faire : traiter create, buy/sell bonding, update/config, mint/burn éventuels, migration/graduate et rattachement au pool tradable.
|
||||
| Version | Decoder / surface | Program id | Objectif |
|
||||
|---:|---|---|---|
|
||||
| `0.7.56` | `meteora_dbc` | `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` | Compléter toutes les instructions/events DBC : launch/bonding, swap exploitable, migration, fees/admin/config. |
|
||||
| `0.7.57` | `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | Parité upstream finale : swaps, bins, positions, liquidity, fees/rewards/admin. |
|
||||
| `0.7.58` | `meteora_damm_v1` | `Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB` | Parité upstream finale : pools, swaps, liquidity, lock, fees/admin. |
|
||||
| `0.7.59` | `meteora_damm_v2` | `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` | Couverture complète : create/custom pools, swaps, liquidity, dynamic config, fees/admin. |
|
||||
| `0.7.60` | `meteora_vault` | `24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi` | Vault deposit/withdraw/fee/accounting ; pas de candle directe. |
|
||||
|
||||
### 6.088. Version `0.7.56` — `meteora_dbc` séparé
|
||||
Objectif : reprendre Meteora après les tranches Raydium et Pump, en séparant bonding/launch, swap effectif, migration et attribution d’origine.
|
||||
#### Bloc programmes système / contexte transactionnel
|
||||
|
||||
À faire : vérifier swaps exploitables, migration, lifecycle, mint/burn éventuels, launch attribution, fees/admin, sans candle artificielle sur events non pricés.
|
||||
| Version | Decoder / surface | Program id | Objectif |
|
||||
|---:|---|---|---|
|
||||
| `0.7.61` | `system_program` | `11111111111111111111111111111111` | Create/assign/transfer account ; side effects de contexte, pas de trade. |
|
||||
| `0.7.62` | `spl_token` | `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` | Transfer, mint, burn, close account, sync native ; base transversale pour deltas. |
|
||||
| `0.7.63` | `spl_token_2022` | `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` | Transfers/extensions Token-2022, mint/burn/close, comptes et side effects. |
|
||||
| `0.7.64` | `associated_token_account` | `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL` | Création ATA, rattachement wallet/token/pool. |
|
||||
| `0.7.65` | `compute_budget` | `ComputeBudget111111111111111111111111111111` | Budget/prioritization fee ; utile scoring/MEV, pas de trade. |
|
||||
| `0.7.66` | `memo` | `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr` | Mémo transactionnel et attribution éventuelle. |
|
||||
| `0.7.67` | `address_lookup_table` | `AddressLookupTab1e1111111111111111111111111` | Résolution/diagnostic ALT si nécessaire. |
|
||||
| `0.7.68` | `mpl_token_metadata` | `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s` | Enrichissement token/NFT/mint metadata. |
|
||||
| `0.7.69` | `mpl_core` | `CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d` | Contexte asset si présent dans corpus. |
|
||||
| `0.7.70` | `bubblegum` | `BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY` | Audit/contexte assets compressés, pas DEX. |
|
||||
|
||||
### 6.089. Version `0.7.57` — `meteora_dlmm` parité upstream finale
|
||||
Objectif : comparer la couverture locale DLMM déjà avancée avec toutes les sources Git/IDL et documenter ou fermer les audits résiduels.
|
||||
#### Bloc routers / aggregators
|
||||
|
||||
À faire : revalider swaps, liquidity, positions, lifecycle, fees/rewards/admin, et garder les discriminants non mappés en audit documenté.
|
||||
| Version | Decoder / surface | Program id | Objectif |
|
||||
|---:|---|---|---|
|
||||
| `0.7.71` | `raydium_routing` | `routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS` | Route/legs Raydium ; éviter le double-count avec AMM/CLMM/CPMM/Stable. |
|
||||
| `0.7.72` | `jupiter_swap_v6` | `JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4` | Route attribution, legs, no duplicate trade/candle. |
|
||||
| `0.7.73` | `jupiter_swap_v4` | `JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB` | Audit/route only si corpus encore utile. |
|
||||
| `0.7.74` | `dflow_aggregator_v4` | `DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH` | Route/intent/orderflow ; pas de double matérialisation. |
|
||||
| `0.7.75` | `okx_dex` | `6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma` | Route attribution ; trades seulement si source exacte non doublonnée. |
|
||||
| `0.7.76` | `onchain_labs_dex_v2` | `proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u` | Corpus d’abord ; classifier route vs DEX effectif. |
|
||||
| `0.7.77` | `titan_router` | `T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT` | Audit route-only sauf preuve de trade direct non doublonné. |
|
||||
| `0.7.78` | `sanctum_router` | `stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq` | Route/liquid staking context ; pas de candle DEX directe. |
|
||||
|
||||
### 6.090. Version `0.7.58` — `meteora_damm_v1` parité upstream finale
|
||||
Objectif : compléter la tranche DAMM v1 déjà engagée, résoudre les surfaces non observées et améliorer le rattachement pool/pair quand possible.
|
||||
#### Bloc DEX avec IDL/code/source exploitable
|
||||
|
||||
À faire : vérifier toutes les instructions upstream restantes, matérialiser uniquement les events prouvés et documenter les cas sans pool/pair local.
|
||||
| Version | Decoder / surface | Program id | Objectif |
|
||||
|---:|---|---|---|
|
||||
| `0.7.79` | `orca_whirlpools` | `whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc` | Swaps, pools, positions, liquidity, fees/rewards. |
|
||||
| `0.7.80` | `stabble_stable_swap` | `swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ` | Stable swap ; deltas exacts, liquidity/admin. |
|
||||
| `0.7.81` | `stabble_weighted_swap` | `swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW` | Weighted swap, deltas exacts, liquidity/admin. |
|
||||
| `0.7.82` | `stabble_clmm` | `6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6` | CLMM Stabble si corpus utile. |
|
||||
| `0.7.83` | `bonkswap` | `BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p` | Swap/liquidity/non-trade. |
|
||||
| `0.7.84` | `boop_fun` | `boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4` | Launch/swap/migration selon corpus. |
|
||||
| `0.7.85` | `byreal_clmm` | `REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2` | CLMM ; corpus puis matérialisation contrôlée. |
|
||||
| `0.7.86` | `fusionamm` | `fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9` | AMM ; swaps/liquidity si corpus. |
|
||||
| `0.7.87` | `goosefx_v1` | `GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT` | DEX/AMM selon corpus. |
|
||||
| `0.7.88` | `goosefx_v2` | `GFXsSL5sSaDfNFQUYsHekbWBW1TsFdjDYzACh62tEHxn` | DEX/AMM selon corpus. |
|
||||
| `0.7.89` | `guac_swap` | `Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1` | Swap/liquidity si corpus. |
|
||||
| `0.7.90` | `hylo_exchange` | `HYEXCHtHkBagdStcJCp3xbbb9B7sdMdWXFNj6mdsG4hn` | Classer DEX/lending/stable selon IDL/corpus. |
|
||||
| `0.7.91` | `printr` | `T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint` | Corpus d’abord ; surface launch/swap à confirmer. |
|
||||
| `0.7.92` | `moonit` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Launch/migration/swap si prouvé. |
|
||||
| `0.7.93` | `metadao_amm_v0_5` | `AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ` | AMM futarchy ; corpus et price semantics. |
|
||||
| `0.7.94` | `metadao_bid_wall` | `WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx` | Order/bid-wall context ; pas de candle directe sans fill exact. |
|
||||
| `0.7.95` | `metadao_launchpad` | `moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM` | Launch/ICO surface ; pas DEX effectif par défaut. |
|
||||
| `0.7.96` | `vertigo` | `vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ` | Swap/launch selon corpus. |
|
||||
| `0.7.97` | `virtuals` | `5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki` | Launch/AMM à confirmer. |
|
||||
| `0.7.98` | `wavebreak` | `waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF` | Corpus et rôle exact. |
|
||||
| `0.7.99` | `woofi` | `WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb` | Swap/route selon corpus. |
|
||||
| `0.7.100` | `pancake_swap` | `HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq` | DEX Solana à confirmer par corpus. |
|
||||
| `0.7.101` | `gavel` | `srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi` | Corpus d’abord ; rôle exact à classer. |
|
||||
| `0.7.102` | `heaven` | `HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o` | Launch/DEX selon corpus. |
|
||||
| `0.7.103` | `lifinity_v2` | `2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c` | DEX legacy/actif à confirmer. |
|
||||
| `0.7.104` | `moonshot` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | À dédupliquer avec `moonit` si même program id. |
|
||||
| `0.7.105` | `openbook_v2` | `opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb` | Audit/orderbook complet ; trade/candle seulement si fills exacts. |
|
||||
| `0.7.106` | `phoenix_v1` | `PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY` | Audit-only complet avant toute matérialisation fill. |
|
||||
|
||||
### 6.091. Version `0.7.59` — `meteora_damm_v2` séparé
|
||||
Objectif : reprendre DAMM v2 comme DEX effectif séparé après disponibilité du ledger de coverage.
|
||||
#### Bloc probes / DEX sans IDL fiable / historiques
|
||||
|
||||
À faire : consolider create_pool, swaps exploitables, configs dynamiques, liquidity, fees/admin, lifecycle ; conserver les swaps sans payload montant/prix fiable comme `non_actionable_trade`.
|
||||
| Version | Decoder / surface | Program id | Objectif |
|
||||
|---:|---|---|---|
|
||||
| `0.7.107` | `alphaq` | `ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA` | Demo3 + corpus ; décider support ou abandon. |
|
||||
| `0.7.108` | `aquifer` | `AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45` | Probe uniquement. |
|
||||
| `0.7.109` | `bisonfi` | `BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi` | Probe uniquement. |
|
||||
| `0.7.110` | `dexlab` | `DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N` | Vérifier support partiel / corpus. |
|
||||
| `0.7.111` | `fluxbeam` | `FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X` | Vérifier support partiel / corpus. |
|
||||
| `0.7.112` | `goonfi` | `goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j` | Probe. |
|
||||
| `0.7.113` | `goonfi_v2` | `goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE` | Probe ; adresse à revérifier si erreur de taille. |
|
||||
| `0.7.114` | `humidifi` | `9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp` | Probe. |
|
||||
| `0.7.115` | `obric_v2` | `obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y` | Probe. |
|
||||
| `0.7.116` | `ondo_global_market` | `XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm` | Rôle marché/tokenized assets à confirmer. |
|
||||
| `0.7.117` | `scorch` | `SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn` | Probe. |
|
||||
| `0.7.118` | `solfi` | `SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe` | Probe. |
|
||||
| `0.7.119` | `solfi_v2` | `SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF` | Probe. |
|
||||
| `0.7.120` | `zerofi` | `ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY` | Probe. |
|
||||
| `0.7.121` | `zora` | `zoRabwLGd5zXaV7Gxacppw8tcceXEiTrSKyNLSaSTUc` | Probe, pas de promotion sans corpus. |
|
||||
| `0.7.122` | `1dex` | `DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm` | Probe. |
|
||||
| `0.7.123` | `aldrin_amm` | `AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6` | Historique/probe. |
|
||||
| `0.7.124` | `aldrin_amm_v2` | `CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4` | Historique/probe. |
|
||||
| `0.7.125` | `crema_finance` | `CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR` | Historique/probe. |
|
||||
| `0.7.126` | `cropper_finance` | `CTMAxxk34HjKWxQ3QLZK1HpaLXmBveao3ESePXbiyfzh` | Historique/probe. |
|
||||
| `0.7.127` | `cropper_whirlpool` | `H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt` | Historique/probe. |
|
||||
| `0.7.128` | `mercurial_stable_swap` | `MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky` | Historique stable swap ; deltas exacts si support. |
|
||||
| `0.7.129` | `saber_stable_swap` | `SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ` | Historique stable swap. |
|
||||
| `0.7.130` | `saros_amm` | `SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr` | Historique/probe. |
|
||||
| `0.7.131` | `step_finance_swap` | `SSwpMgqNDsyV7mAgN9ady4bDVu5ySjmmXejXvy2vLt1` | Historique/probe. |
|
||||
| `0.7.132` | `stepn_dooar_swap` | `Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j` | Historique/probe. |
|
||||
| `0.7.133` | `raydium_amm_v2_legacy` | `RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr` | Historique Raydium ; corpus d’abord. |
|
||||
| `0.7.134` | `raydium_amm_v3_legacy` | `27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv` | Historique Raydium ; ne pas confondre avec CLMM moderne. |
|
||||
| `0.7.135` | `raydium_pool_v4_json_audit` | aucun `program_id` prouvé par le fichier seul | Vérifier `sol-parser-sdk/idls/raydium_pool_v4.json` après les surfaces documentées ; patch AMM v4 si amélioration, sinon clôture no-op. |
|
||||
|
||||
### 6.092. Version `0.7.60` — `phoenix_v1` audit-only complet
|
||||
Objectif : finir tous les events Git disponibles en audit, sans activer de trade/candle.
|
||||
#### Nettoyage / consolidation
|
||||
|
||||
À faire : couvrir `Fill`, `FillSummary`, `Fee`, `Evict`, `ExpiredOrder` et autres logs/events disponibles ; préparer le futur modèle orderbook sans matérialisation marché par défaut.
|
||||
| Version | Scope | Objectif |
|
||||
|---:|---|---|
|
||||
| `0.7.136` | cleanup `SOLSCAN_ACCOUNT_SOURCES` | Retirer les doublons/promotions : les vrais programmes validés deviennent constantes + support matrix ; les comptes non-programmes restent contexte ou sont supprimés. |
|
||||
| `0.7.137` | base neuve multi-programmes | Replay consolidé, coverage global, zéro faux trade/candle, diagnostics bloquants à zéro. |
|
||||
|
||||
### 6.093. Version `0.7.61` — `openbook_v2` audit-only complet
|
||||
Objectif : finir les layouts logs/events OpenBook v2 et définir les conditions futures de matérialisation orderbook/trade.
|
||||
|
||||
À faire : vérifier fills, settle, consume events, open orders create/close, maker/taker, lots/decimals et sens économique avant toute promotion.
|
||||
|
||||
### 6.094. Version `0.7.62` — `orca_whirlpools` event coverage
|
||||
Objectif : reprendre Whirlpools depuis IDL/source avec corpus dédié.
|
||||
|
||||
À faire : swaps, pools, positions, liquidity, fees/rewards, tick arrays, mint/burn/Token-2022 si applicable.
|
||||
|
||||
### 6.095. Version `0.7.63+` — Launch surfaces, DEX historiques/candidats et validation consolidée
|
||||
Objectif : traiter les surfaces restantes puis rejouer une base neuve multi-DEX.
|
||||
|
||||
À faire : Moonshot/Moonit, Boop, Heaven, Bags, LetsBonk, FluxBeam, DexLab, Lifinity, Stabble, BonkSwap, GooseFX, Obric, SolFi et autres entrées Vybe/registry ; rapport coverage par DEX/event, zéro faux trade/candle, corpus documentés, matrices cohérentes, diagnostics bloquants à zéro.
|
||||
Garde-fous constants : pas de faux trade, pas de fausse candle, pas de `program_id` fictif, pas de promotion sans corpus transactionnel local, pas de double matérialisation router/leg, pas de logique métier DEX profonde dans `kb_demo_app`.
|
||||
|
||||
### 6.091. Version `0.8.x` — Analyse et filtrage
|
||||
Objectif : transformer les événements bruts en signaux exploitables.
|
||||
@@ -1561,23 +1731,16 @@ Ordre de travail recommandé pour la suite :
|
||||
2. `0.7.45` : `meteora_dlmm` — clos ;
|
||||
3. `0.7.46` : `meteora_damm_v1` — clos côté corpus local ;
|
||||
4. `0.7.47` : Upstream Git Registry / DEX discovery preparation — acquis ;
|
||||
5. `0.7.48-pre` : event coverage + DB model checkpoint — clos après table, sync upstream, refresh counts, diagnostics et profil validation ;
|
||||
5. `0.7.48-pre` : event coverage + DB model checkpoint — clos ;
|
||||
6. `0.7.48` : `raydium_cpmm` — clos ;
|
||||
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_swap` — clôturé ;
|
||||
11. `0.7.53` : `raydium_pool_v4` audit conditionnel ;
|
||||
12. `0.7.54` : `pump_swap` ;
|
||||
13. `0.7.55` : `pump_fun` ;
|
||||
14. `0.7.56` : `meteora_dbc` ;
|
||||
15. `0.7.57` : `meteora_dlmm` parité upstream finale ;
|
||||
16. `0.7.58` : `meteora_damm_v1` parité upstream finale ;
|
||||
17. `0.7.59` : `meteora_damm_v2` ;
|
||||
18. `0.7.60` : `phoenix_v1` audit-only complet ;
|
||||
19. `0.7.61` : `openbook_v2` audit-only complet ;
|
||||
20. `0.7.62` : `orca_whirlpools` ;
|
||||
21. `0.7.63+` : launch surfaces, DEX candidats/historiques et validation consolidée.
|
||||
9. `0.7.51` : `raydium_amm_v4` — clos ;
|
||||
10. `0.7.52` : `raydium_stable_swap` — clos ;
|
||||
11. `0.7.53` : `pump_swap` / `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA` — clos ;
|
||||
12. `0.7.54` : `pump_fees` / `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` ;
|
||||
13. `0.7.55` : `pump_fun` / `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` ;
|
||||
14. `0.7.56+` : appliquer le phasage strict “une version = un `program_id`” défini en section `6.085`.
|
||||
|
||||
Garde-fous constants :
|
||||
|
||||
@@ -1649,7 +1812,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_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.
|
||||
La suite après `0.7.52 raydium_stable_swap` a été clôturée par `0.7.53 pump_swap`, puis continue avec le phasage strict “une version = un `program_id`”. `raydium_pool_v4.json` reste repoussé vers la fin comme audit conditionnel : source Git/IDL utile seulement si elle apporte une amélioration concrète à `raydium_amm_v4` ou prouve un nouveau scope par corpus local.
|
||||
|
||||
## Clôture `0.7.51` — Raydium AMM v4
|
||||
|
||||
@@ -1674,7 +1837,7 @@ 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 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.
|
||||
La tranche `0.7.52 raydium_stable_swap` est clôturée et `0.7.53 pump_swap` est désormais clôturé également. L'audit `raydium_pool_v4.json` reste repoussé vers la fin du phasage, avant le nettoyage/consolidation, afin de ne pas bloquer les surfaces Pump/Meteora/système/routers/DEX documentés.
|
||||
|
||||
### Addendum final — `0.7.52 raydium_stable_swap`
|
||||
|
||||
@@ -1723,3 +1886,11 @@ SQL de validation : `validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sq
|
||||
|
||||
Rapport : `docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md`.
|
||||
|
||||
### Addendum — `0.7.53 pump_swap`
|
||||
|
||||
La reprise après `0.7.52 raydium_stable_swap` cible uniquement le program id `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA`. Le decoder local `pump_swap` couvre désormais les discriminants d’instructions upstream connus : trades matérialisables (`buy`, `sell`), swap decoded-only provisoire (`buy_exact_quote_in` tant que les montants exacts ne sont pas prouvés), liquidity (`deposit`, `withdraw`), pool/config (`create_pool`, `create_config`, `update_fee_config`), creator/protocol fee paths, cashback/token incentives et volume accumulator. Les events Program-data associés sont conservés comme entrées de coverage explicites ; ils ne doivent pas créer de doublon trade si l’instruction locale matérialise déjà le swap effectif.
|
||||
|
||||
Delta post-replay : `toggle_cashback_enabled` est admin-only, `migrate_pool_coin_creator` est admin/config et l’index `k_sol_instruction_observations` nomme les discriminants PumpSwap observés. Les trois discriminants d’abord inconnus (`01214eb921432c5c`, `fbe0ab92a01a71e9`, `cfbdb247a77a44b4`) sont maintenant nommés : `transfer_creator_fees_to_pump_v2` et `update_buyback_config` sont confirmés par le raw Solscan IDL ; `set_reserved_fee_recipient` reste une entrée observée dans les logs locaux, probablement une instruction ancienne/supprimée ou non exposée dans ce raw.
|
||||
|
||||
Critères de fermeture : corpus Demo3/backfill/replay dédié, coverage `pump_swap` synchronisée, zéro fallback `upstream_git.instruction_match` pour les instructions couvertes localement, failed tx sans trade/candle, non-swap sans trade/candle, et SQL `validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql` vide sur les requêtes d’anomalies.
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
# DEX Decoder Matrix — `khadhroony-bobobot` `0.7.50-pre-r2`
|
||||
# DEX Decoder Matrix — `khadhroony-bobobot` `0.7.53 final`
|
||||
|
||||
## Note `0.7.53 final` — PumpSwap clôturé et sources IDL locales
|
||||
|
||||
Le répertoire `idls/` devient une source locale de savoir en plus des liens Git. Les IDL Solscan locales doivent être comparées au registre upstream et au corpus avant promotion métier. `pump_swap` est clôturé côté transaction/log decoder : instructions IDL, events Anchor audit-only, `buy_exact_quote_in` via `BuyEvent` exact, tests synthétiques et SQL global. Raydium AMM v4 / CLMM / CPMM ne nécessitent pas de correction dans cette clôture ; les gaps Meteora sont reportés.
|
||||
|
||||
`sol-parser-sdk/idls/raydium_pool_v4.json` a été vérifié comme source annexe distincte des fichiers `idls/raydium_*.json` présents localement : il expose notamment `swapBaseIn` et des comptes OpenBook/Serum, mais aucun fichier local ne porte ce nom ni ne correspond à son empreinte/format. Il reste donc un audit conditionnel, pas une source bloquante pour `0.7.53`.
|
||||
|
||||
Cette matrice complète `kb_lib/src/dex_support_matrix.rs`. Elle documente **ce qui est fait**, **ce qui reste à faire**, et **le niveau de preuve attendu** par DEX/version.
|
||||
|
||||
@@ -17,7 +23,7 @@ Cette matrice complète `kb_lib/src/dex_support_matrix.rs`. Elle documente **ce
|
||||
|
||||
- Carbon decoders : `https://github.com/sevenlabs-hq/carbon/tree/main/decoders`
|
||||
- Solana Streamer : `https://github.com/0xfnzero/solana-streamer`
|
||||
- Sol Parser SDK IDLs : `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl`
|
||||
- Sol Parser SDK IDLs : `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idls`
|
||||
- Pinax Substreams Solana IDLs : `https://github.com/pinax-network/substreams-solana-idls/tree/main/src`
|
||||
- HODL Warden Solana Tx Parser : `https://github.com/hodlwarden/solana-tx-parser/tree/main/src`
|
||||
- OpenBook v2 : `https://github.com/openbook-dex/openbook-v2`
|
||||
@@ -33,8 +39,8 @@ Cette matrice complète `kb_lib/src/dex_support_matrix.rs`. Elle documente **ce
|
||||
| 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. | 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. |
|
||||
| 6 | `raydium_pool_v4` | `to_verify / late-phase 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.53 closed` | `buy`, `sell` + `buy_exact_quote_in` matérialisable via `BuyEvent` exact ; instructions non-trade spécialisées : liquidity, fee/creator fee, admin/config, cashback/token incentives, volume accumulator ; events Anchor autonomes audit-only. | Trades/candles uniquement depuis montants exacts ; failed tx decoded-only ; `instruction_bounds_only` reste decoded-only ; tests synthétiques IDL et SQL global ajoutés. |
|
||||
| 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. |
|
||||
| 9 | `meteora_dbc` | `partial / 0.7.56 planned` | Swaps/instruction audits observés ; Demo3 donne du corpus. | Couverture complète DBC : launch/bonding curve, swap, migration, config/admin, fees ; matérialiser seulement ce qui est prouvé. |
|
||||
| 10 | `meteora_dlmm` | `supported / 0.7.57 parity` | Couverture avancée validée en `0.7.45` : swaps, liquidity, positions, lifecycle, fees ; non-trade matérialisé. | Résoudre les audits résiduels non mappés ; comparer Carbon/IDL pour events rewards/admin restants ; revalidation base neuve. |
|
||||
@@ -273,3 +279,9 @@ La tranche a été validée sur base SQLite dédiée : tous les discriminants `0
|
||||
|---|---|---|---|---|
|
||||
| `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. |
|
||||
|
||||
## 0.7.53 — PumpSwap
|
||||
|
||||
| Decoder | Program id | Statut | Source discriminants | Couverture locale | Règles métier |
|
||||
|---|---|---:|---|---|---|
|
||||
| `pump_swap` | `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA` | supported / 0.7.53 closed | upstream registry + `idls/pump_swap.pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA.json` + corpus Demo3/replay | instructions : `buy`, `sell`, `buy_exact_quote_in`, `deposit`, `withdraw`, `create_pool`, `create_config`, `update_fee_config`, creator-fee, cashback, token incentives, volume accumulator, admin/config ; events Anchor autonomes audit-only | `buy_exact_quote_in` trade uniquement avec `pump_swap_anchor_buy_event`; aucun non-swap en trade/candle ; failed tx decoded-only ; `buy_event`/`sell_event` Program-data audit-only ; `transfer_creator_fees_to_pump_v2` et `update_buyback_config` confirmés par Solscan IDL ; `set_reserved_fee_recipient` conservé sur preuve log locale |
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# DEX Event Coverage Matrix — `khadhroony-bobobot` `0.7.50-pre-r2`
|
||||
# DEX Event Coverage Matrix — `khadhroony-bobobot` `0.7.53 final`
|
||||
|
||||
Cette matrice complète `docs/DEX_DECODER_MATRIX.md` avec une lecture par familles d'événements. Elle ne remplace pas la preuve locale : une entrée Git/IDL reste un indice tant qu'elle n'est pas observée dans le corpus local puis validée par replay et SQL.
|
||||
|
||||
@@ -214,3 +214,38 @@ Status: **closed on local corpus**.
|
||||
|
||||
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.
|
||||
|
||||
## 0.7.53 — `pump_swap`
|
||||
|
||||
Program id unique : `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA`.
|
||||
|
||||
| Entry | Discriminator | Family | Expected DB target | Local event kind | Status |
|
||||
|---|---:|---|---|---|---|
|
||||
| `buy` | `66063d1201daebea` | `swap` | `k_sol_trade_events` | `pump_swap.buy` | local specialized decoder ; materialize only from exact transfer/vault deltas |
|
||||
| `sell` | `33e685a4017f83ad` | `swap` | `k_sol_trade_events` | `pump_swap.sell` | local specialized decoder ; materialize only from exact transfer/vault deltas |
|
||||
| `buy_exact_quote_in` | `c62e1552b4d9e870` | `swap` | `k_sol_trade_events` only when exact Anchor `BuyEvent` is present ; otherwise decoded-only | `pump_swap.buy_exact_quote_in` | local specialized decoder ; `amountSource=pump_swap_anchor_buy_event` materializes trades ; `instruction_bounds_only` rows keep explicit `skipTradeReason` |
|
||||
| `create_pool` | `e992d18ecf6840bc` | `pool_create` | `k_sol_pool_lifecycle_events` or decoded-only | `pump_swap.create_pool` | local specialized instruction ; non-trade |
|
||||
| `deposit` | `f223c68952e1f2b6` | `liquidity_add` | `k_sol_liquidity_events` or decoded-only | `pump_swap.deposit` | local specialized instruction ; non-trade |
|
||||
| `withdraw` | `b712469c946da122` | `liquidity_remove` | `k_sol_liquidity_events` or decoded-only | `pump_swap.withdraw` | local specialized instruction ; non-trade |
|
||||
| `collect_coin_creator_fee` | `a039592ab58b2b42` | `fee` | `k_sol_fee_events` or decoded-only | `pump_swap.collect_coin_creator_fee` | local specialized instruction ; non-trade |
|
||||
| `transfer_creator_fees_to_pump` | `8b348655e4e56cf1` | `fee` | `k_sol_fee_events` or decoded-only | `pump_swap.transfer_creator_fees_to_pump` | local specialized instruction ; non-trade |
|
||||
| `transfer_creator_fees_to_pump_v2` | `01214eb921432c5c` | `fee` | `k_sol_fee_events` or decoded-only | `pump_swap.transfer_creator_fees_to_pump_v2` | Solscan IDL proof + local log proof: `transfer_creator_fees_to_pump_v2` / `Instruction: TransferCreatorFeesToPumpV2` ; non-trade |
|
||||
| `claim_cashback` | `253a237ebe35e4c5` | `reward` | `k_sol_reward_events` or decoded-only | `pump_swap.claim_cashback` | local specialized instruction ; non-trade |
|
||||
| `claim_token_incentives` | `1004471ccc01281b` | `reward` | `k_sol_reward_events` or decoded-only | `pump_swap.claim_token_incentives` | local specialized instruction ; non-trade |
|
||||
| `init_user_volume_accumulator` | `5e06ca73ff60e8b7` | `reward` | `k_sol_reward_events` or decoded-only | `pump_swap.init_user_volume_accumulator` | local specialized instruction ; non-trade |
|
||||
| `sync_user_volume_accumulator` | `561fc057a3574fee` | `reward` | `k_sol_reward_events` or decoded-only | `pump_swap.sync_user_volume_accumulator` | local specialized instruction ; non-trade |
|
||||
| `close_user_volume_accumulator` | `f945a4da9667548a` | `reward` | `k_sol_reward_events` or decoded-only | `pump_swap.close_user_volume_accumulator` | local specialized instruction ; non-trade |
|
||||
| `update_buyback_config` | `fbe0ab92a01a71e9` | `admin_config` | `k_sol_pool_admin_events` or decoded-only | `pump_swap.update_buyback_config` | Solscan IDL proof + local log proof: `update_buyback_config` / `Instruction: UpdateBuybackConfig` ; non-trade |
|
||||
| `set_reserved_fee_recipient` | `cfbdb247a77a44b4` | `admin_config` | `k_sol_pool_admin_events` or decoded-only | `pump_swap.set_reserved_fee_recipient` | local log proof only: `Instruction: SetReservedFeeRecipient` ; absent from checked Solscan IDL raw ; non-trade |
|
||||
| admin/config group | see report | `admin_config` | `k_sol_pool_admin_events` or decoded-only | `pump_swap.*` | local specialized instruction ; non-trade ; includes `toggle_cashback_enabled` and `migrate_pool_coin_creator` as admin-only |
|
||||
| `buy_event` / `sell_event` | `67f4521f2cf57777` / `3e2f370aa503dc2a` | `swap_event_audit` | decoded-only | not local-instruction mapped | Program-data event discriminators listed; not used to duplicate local instruction trades |
|
||||
| auxiliary Program-data events | see report | fee/reward/admin/liquidity | decoded-only until payload-specific materializer exists | not local-instruction mapped | explicit upstream status required after replay |
|
||||
|
||||
|
||||
|
||||
### Fermeture `0.7.53`
|
||||
|
||||
- `pump_swap` ne présente plus de decoded event local sans coverage dans le corpus de clôture.
|
||||
- `buy_exact_quote_in` est matérialisé seulement quand le `BuyEvent` Anchor donne les montants exacts ; les bornes d’instruction seules restent non actionnables.
|
||||
- Les events Anchor `*_event` sont décodés en audit-only pour éviter les doublons, sauf exception matérialisable explicitement testée.
|
||||
- Les gaps globaux restants sont classés comme backlog upstream (`pump_fees`, `pump_fun`, `jupiter_swap`, agrégateurs), gaps Meteora reportés, ou observations non attribuées.
|
||||
- Les checks Raydium AMM v4 / CLMM / CPMM normalisés sont vides ; aucune correction Raydium n’est incluse dans cette clôture.
|
||||
|
||||
150
docs/prompts/PROMPT_0_7_53_PUMP_SWAP.md
Normal file
150
docs/prompts/PROMPT_0_7_53_PUMP_SWAP.md
Normal file
@@ -0,0 +1,150 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_53_PUMP_SWAP.md -->
|
||||
|
||||
# Prompt de reprise — `0.7.53 pump_swap`
|
||||
|
||||
Nous reprenons le workspace Rust/Tauri `khadhroony-bobobot` après le commit final `0.7.52 raydium_stable_swap`.
|
||||
|
||||
## Objectif de tranche
|
||||
|
||||
Version cible : `0.7.53`
|
||||
|
||||
Surface cible unique : `pump_swap`
|
||||
|
||||
Program id cible unique :
|
||||
|
||||
```text
|
||||
pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA
|
||||
```
|
||||
|
||||
Règle de phasage validée : **une version = un `program_id`**.
|
||||
|
||||
`raydium_pool_v4.json` est explicitement repoussé vers la fin du phasage. Il ne doit pas bloquer `0.7.53`.
|
||||
|
||||
## Contexte validé avant reprise
|
||||
|
||||
Raydium est clos sur les surfaces suivantes :
|
||||
|
||||
- `raydium_cpmm` — `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C` ;
|
||||
- `raydium_clmm` — `CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK` ;
|
||||
- `raydium_launchpad` — `LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj` ;
|
||||
- `raydium_amm_v4` — `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` ;
|
||||
- `raydium_stable_swap` — `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`.
|
||||
|
||||
`0.7.52 raydium_stable_swap` est clos avec :
|
||||
|
||||
- `cargo test -p kb_lib` : `407 passed`, `0 failed` ;
|
||||
- `cargo clippy -p kb_lib --all-targets -- -D warnings` : OK ;
|
||||
- swaps matérialisés uniquement depuis `amountSource=stable_swap_vault_balance_delta` ;
|
||||
- failed transactions conservées decoded-only ;
|
||||
- aucun successful swap non expliqué.
|
||||
|
||||
## Sources à utiliser pour `pump_swap`
|
||||
|
||||
Sources obligatoires à vérifier avant de patcher :
|
||||
|
||||
- `kb_lib/src/constants.rs` et `SOLSCAN_ACCOUNT_SOURCES` ;
|
||||
- sources upstream Git déjà intégrées dans le registre : Carbon, fnzero, Pinax, HODL Warden si disponibles ;
|
||||
- IDL Solscan du programme `pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA` si disponible ;
|
||||
- corpus local Demo3 + backfill signature/pool ;
|
||||
- `k_sol_dex_event_coverage_entries` après replay.
|
||||
|
||||
Les sources Git/IDL/Solscan sont des indices. La preuve métier exige corpus local, replay et SQL.
|
||||
|
||||
## Tâches attendues
|
||||
|
||||
1. Inspecter le support local existant de `pump_swap`.
|
||||
2. Lister toutes les instructions/events/discriminators disponibles depuis les sources upstream/IDL.
|
||||
3. Comparer avec les events localement couverts.
|
||||
4. Compléter le decoder `pump_swap` pour couvrir au minimum :
|
||||
- `buy` ;
|
||||
- `sell` ;
|
||||
- fees / creator fees / protocol fees si présents ;
|
||||
- admin/config si présents ;
|
||||
- events auxiliaires tels que cashback, volume accumulator ou équivalents si présents dans les sources.
|
||||
5. Matérialiser en `k_sol_trade_events` et `k_sol_pair_candles` uniquement si les montants exacts et le sens économique sont prouvés.
|
||||
6. Conserver les failed transactions comme decoded-only avec `failed_transaction`.
|
||||
7. Matérialiser les non-trade uniquement vers les tables adaptées : liquidity, fee, admin, lifecycle, reward, orderbook ou decoded-only selon le cas.
|
||||
8. Nettoyer les fallbacks `upstream_git.instruction_match` uniquement quand un decoder local spécialisé couvre vraiment l’entrée.
|
||||
9. Mettre à jour la coverage DB et la matrice documentaire.
|
||||
10. Ajouter ou mettre à jour le SQL de validation dédié : `validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql`.
|
||||
|
||||
## Invariants obligatoires
|
||||
|
||||
- Aucun non-swap ne doit créer de trade/candle.
|
||||
- Aucune transaction failed ne doit créer de trade/candle.
|
||||
- Aucun trade/candle ne doit être créé depuis des bornes d’instruction ou des montants incomplets.
|
||||
- Aucun router/aggregator ne doit créer un doublon si le DEX effectif matérialise déjà le trade.
|
||||
- Aucun `program_id` ne doit être inventé.
|
||||
- Aucun compte non-programme de `SOLSCAN_ACCOUNT_SOURCES` ne doit être promu en decoder autonome.
|
||||
- `kb_demo_app` ne doit pas contenir de logique métier DEX profonde.
|
||||
|
||||
## Contraintes de code
|
||||
|
||||
Respecter les contraintes du projet :
|
||||
|
||||
- Rust 2024 ;
|
||||
- aucun fichier `mod.rs` ;
|
||||
- pas de `pub mod` ; utiliser `mod` + `pub use` ;
|
||||
- pas de `anyhow`, pas de `thiserror` ;
|
||||
- pas de `?`, `unwrap`, `expect` dans le code applicatif `kb_lib` ;
|
||||
- gestion d’erreurs explicite via `match`, `if let Err`, `let Err = ... else` ;
|
||||
- rustdoc publique ;
|
||||
- `#![deny(unreachable_pub)]` et `#![warn(missing_docs)]` ;
|
||||
- tracing obligatoire ;
|
||||
- tests offline ;
|
||||
- si une requête DB est ajoutée ou modifiée, mettre à jour les re-exports dans `kb_lib/src/db.rs`, puis dans `kb_lib/src/lib.rs`.
|
||||
|
||||
## Validation attendue
|
||||
|
||||
Commandes locales à exécuter après patch :
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo test -p kb_lib
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
Replay attendu sur une base dédiée `0.7.53 pump_swap` :
|
||||
|
||||
```text
|
||||
skipDexDecode=no
|
||||
forceDexDecode=yes
|
||||
deferInstructionObservations=yes
|
||||
```
|
||||
|
||||
SQL de clôture attendu :
|
||||
|
||||
- coverage par entrée `pump_swap` ;
|
||||
- instruction observations ;
|
||||
- absence d’audit résiduel local non expliqué ;
|
||||
- absence de fallback upstream pour les entrées couvertes localement ;
|
||||
- failed tx -> zéro trade ;
|
||||
- non-swap -> zéro trade ;
|
||||
- decoded without coverage -> vide ;
|
||||
- successful non-materialized inexpliqués -> vide ;
|
||||
- multi-target materialization -> vide ;
|
||||
- résumé matérialisation par event_kind.
|
||||
|
||||
## Livrables documentaires
|
||||
|
||||
Mettre à jour au minimum :
|
||||
|
||||
- `ROADMAP.md` ;
|
||||
- `CHANGELOG.md` ;
|
||||
- `docs/DEX_DECODER_MATRIX.md` ;
|
||||
- `docs/DEX_EVENT_COVERAGE_MATRIX.md` ;
|
||||
- `docs/reports/PUMP_SWAP_EVENT_COVERAGE_REPORT.md` ;
|
||||
- `validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql`.
|
||||
|
||||
## Décision attendue en fin de tranche
|
||||
|
||||
`0.7.53 pump_swap` est clôturable uniquement si :
|
||||
|
||||
```text
|
||||
- tous les events/instructions disponibles ont un statut explicite ;
|
||||
- les swaps réussis exploitables produisent trades/candles ;
|
||||
- les failed transactions restent decoded-only ;
|
||||
- les non-trade sont matérialisés dans les bonnes tables ou restent decoded-only expliqués ;
|
||||
- la coverage DB ne contient pas de gap local inexpliqué ;
|
||||
- cargo test et clippy sont OK.
|
||||
```
|
||||
272
docs/prompts/PROMPT_0_7_54_PUMP_FUN.md
Normal file
272
docs/prompts/PROMPT_0_7_54_PUMP_FUN.md
Normal file
@@ -0,0 +1,272 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_54_PUMP_FUN.md -->
|
||||
|
||||
# Prompt de reprise — khadhroony-bobobot 0.7.54 — pump_fun
|
||||
|
||||
Tu reprends le workspace Rust/Tauri `khadhroony-bobobot` après clôture documentaire et fonctionnelle de `0.7.53 pump_swap`.
|
||||
|
||||
## 1. Fichiers à utiliser comme base
|
||||
|
||||
Je fournis l’archive la plus récente du workspace, intégrant normalement les deltas de clôture `0.7.53`.
|
||||
|
||||
À considérer comme sources locales de savoir :
|
||||
|
||||
- le code Rust du workspace ;
|
||||
- les fichiers Markdown (`README.md`, `ROADMAP.md`, `CHANGELOG.md`, `docs/**`) ;
|
||||
- les SQL de validation dans `validation_sql/**` ;
|
||||
- le répertoire `idls/**`, ajouté au projet, contenant des IDL JSON téléchargés depuis Solscan ;
|
||||
- les liens Git/upstream déjà documentés dans les docs ;
|
||||
- les résultats SQL/logs que je colle dans la conversation.
|
||||
|
||||
Ne pas supposer que les docs sont parfaites : les vérifier contre le code et contre les IDL locales.
|
||||
|
||||
## 2. État validé avant cette version
|
||||
|
||||
La version `0.7.53` a fermé `pump_swap` côté transaction/log decoder :
|
||||
|
||||
- `cargo test -p kb_lib` : `421 passed`;
|
||||
- `cargo clippy -p kb_lib --all-targets -- -D warnings` : OK ;
|
||||
- `pump_swap.buy`, `pump_swap.sell`, `pump_swap.buy_exact_quote_in` matérialisent correctement les trades ;
|
||||
- `buy_exact_quote_in` utilise `pump_swap_anchor_buy_event` quand l’Anchor `BuyEvent` exact est disponible ;
|
||||
- les `*_event` Anchor PumpSwap sont décodés en audit-only sauf exception métier explicite ;
|
||||
- `claim_token_incentives_event` est prêt à matérialiser `k_sol_reward_events` si un event réussi apparaît ;
|
||||
- `pump_swap` ne présente plus de decoded event sans coverage, ni fallback upstream résiduel, ni trade candidate réussi non matérialisé ;
|
||||
- les surfaces Raydium déjà travaillées (`raydium_amm_v4`, `raydium_clmm`, `raydium_cpmm`) ne doivent pas être rouvertes sauf bug prouvé ;
|
||||
- les petits gaps Meteora sont volontairement différés.
|
||||
|
||||
Ne pas modifier PumpSwap ou Raydium sauf preuve SQL/code claire d’une régression.
|
||||
|
||||
## 3. Objectif de la version 0.7.54
|
||||
|
||||
Objectif principal : ouvrir et avancer une tranche `pump_fun`.
|
||||
|
||||
Cette tranche doit traiter la surface launch/mint Pump.fun, qui est logiquement prioritaire avant `pump_fees`.
|
||||
|
||||
Le backlog global montre des entrées `pump_fun` encore en fallback upstream, notamment :
|
||||
|
||||
- `pump_fun.collect_creator_fee` / discriminator `1416567bc61cdb84` ;
|
||||
- `pump_fun.migrate_bonding_curve_creator` / `577c34bf3426d6e8` ;
|
||||
- `pump_fun.distribute_creator_fees` / `a572670079cef751` ;
|
||||
- `pump_fun.admin_set_creator` / `4519ab8e39ef0d04` ;
|
||||
- `pump_fun.extend_account` / `ea66c2cb96483ee5` ;
|
||||
- `pump_fun.set_creator` / `fe94ff70cf8eaaa5` ;
|
||||
- `pump_fun.migrate` / `9beae792ec9ea21e` ;
|
||||
- `pump_fun.claim_cashback` / `253a237ebe35e4c5` ;
|
||||
- `pump_fun.sell` / `33e685a4017f83ad` ;
|
||||
- autres discriminators `pump_fun` observés dans `k_sol_instruction_observations`.
|
||||
|
||||
L’objectif n’est pas seulement de faire disparaître un fallback : il faut couvrir proprement la surface `pump_fun` :
|
||||
|
||||
- registry/coverage ;
|
||||
- decoder local ou statut local explicitement decoded-only/audit-only ;
|
||||
- matérialisation métier si les données sont fiables ;
|
||||
- tests unitaires ;
|
||||
- SQL de validation ;
|
||||
- documentation.
|
||||
|
||||
## 4. Périmètre
|
||||
|
||||
### Inclus
|
||||
|
||||
- `pump_fun` launch/mint/bonding-curve surface ;
|
||||
- instructions/events liés à création/migration/configuration/creator fees/cashback si présents dans IDL ou corpus ;
|
||||
- intégration coverage ;
|
||||
- matérialisation vers tables métier seulement si fiable.
|
||||
|
||||
### Hors périmètre sauf nécessité démontrée
|
||||
|
||||
- `pump_swap`, déjà fermé en `0.7.53` ;
|
||||
- `raydium_*`, sauf régression prouvée ;
|
||||
- `meteora_*`, volontairement différé ;
|
||||
- `jupiter_swap`, `dflow_aggregator_v4`, `onchain_labs_dex_v2`, `orca_whirlpools`, backlog futur ;
|
||||
- `pump_fees`, qui doit venir après `pump_fun`, probablement en `0.7.55`.
|
||||
|
||||
## 5. Méthode obligatoire
|
||||
|
||||
### 5.1 Nouvelle base SQLite
|
||||
|
||||
Créer une nouvelle DB dédiée à `0.7.54`, ne pas travailler sur l’ancienne DB de validation PumpSwap.
|
||||
|
||||
Démarrage attendu :
|
||||
|
||||
- catalog initial propre ou connu ;
|
||||
- backfills ciblés ;
|
||||
- replay forcé ;
|
||||
- validation SQL.
|
||||
|
||||
### 5.2 Backfill de corpus
|
||||
|
||||
Construire un corpus local à partir de :
|
||||
|
||||
1. filtres Solscan.io quand disponibles ;
|
||||
2. Demo3 discovery quand nécessaire ;
|
||||
3. batch backfill de groupes de signatures ;
|
||||
4. program/signature backfill si pertinent ;
|
||||
5. signatures issues des requêtes SQL `sample_signature`.
|
||||
|
||||
Utiliser d’abord les signatures fortes observées dans le backlog :
|
||||
|
||||
- `pump_fun.collect_creator_fee`;
|
||||
- `pump_fun.migrate_bonding_curve_creator`;
|
||||
- `pump_fun.distribute_creator_fees`;
|
||||
- `pump_fun.admin_set_creator`;
|
||||
- `pump_fun.extend_account`;
|
||||
- `pump_fun.set_creator`;
|
||||
- `pump_fun.migrate`;
|
||||
- `pump_fun.claim_cashback`;
|
||||
- puis autres discriminators observés.
|
||||
|
||||
Après chaque groupe de backfill :
|
||||
|
||||
- replay local avec `skipDexDecode=no`;
|
||||
- utiliser `forceDexDecode=yes` quand le decoder/coverage change ;
|
||||
- `deferInstructionObservations=yes` ;
|
||||
- rafraîchir catalog ;
|
||||
- relancer les SQL de surveillance.
|
||||
|
||||
### 5.3 Sources
|
||||
|
||||
Utiliser en priorité :
|
||||
|
||||
- `idls/**` local ;
|
||||
- code existant ;
|
||||
- docs existantes ;
|
||||
- `upstream_registry_generated.rs` ;
|
||||
- sources Git déjà référencées dans les docs ;
|
||||
- Solscan signatures/logs ;
|
||||
- payloads locaux DB.
|
||||
|
||||
Si une IDL locale contredit une source Git, signaler la divergence et ne pas inventer.
|
||||
|
||||
## 6. Contraintes de code Rust
|
||||
|
||||
Respecter strictement les conventions du projet :
|
||||
|
||||
- Rust 2024 ;
|
||||
- pas de `?` ;
|
||||
- pas de `unwrap()` / `expect()` en code applicatif ;
|
||||
- pas de `anyhow` / `thiserror` ;
|
||||
- `match` / `if let Err` explicites ;
|
||||
- async-first ;
|
||||
- `tracing` obligatoire ;
|
||||
- pas de `mod.rs` ;
|
||||
- pas de `pub mod` ; utiliser `mod` + `pub use` ;
|
||||
- imports limités, types appelés de façon qualifiée quand c’est la convention locale ;
|
||||
- tests offline ;
|
||||
- ne pas casser `#![deny(unreachable_pub)]` et `#![warn(missing_docs)]`.
|
||||
|
||||
Si des requêtes DB sont ajoutées ou déplacées, penser aux re-exports :
|
||||
|
||||
- `kb_lib/src/db.rs` ;
|
||||
- `kb_lib/src/lib.rs`.
|
||||
|
||||
## 7. Matérialisation attendue
|
||||
|
||||
Pour `pump_fun`, ne pas forcer une matérialisation si les montants/acteurs/comptes ne sont pas prouvés.
|
||||
|
||||
Classer explicitement chaque entrée :
|
||||
|
||||
- `k_sol_launch_events` pour les événements de launch/mint/migration ;
|
||||
- `k_sol_fee_events` si l’instruction représente réellement des frais exploitables ;
|
||||
- `k_sol_pool_admin_events` si c’est de la configuration/admin/creator ;
|
||||
- `k_sol_reward_events` uniquement si c’est réellement une récompense/incitation/cashback fiable ;
|
||||
- `k_sol_dex_decoded_events_only` si audit-only ou données insuffisantes ;
|
||||
- `k_sol_trade_events` seulement si c’est un swap/trade fiable ;
|
||||
- `skip*Reason` explicite quand non matérialisable.
|
||||
|
||||
Ne jamais matérialiser une transaction failed comme business event.
|
||||
|
||||
## 8. SQL de validation à utiliser
|
||||
|
||||
Utiliser et adapter :
|
||||
|
||||
- `validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql`;
|
||||
- les SQL de validation PumpSwap comme modèle ;
|
||||
- une nouvelle validation dédiée à `pump_fun`, par exemple :
|
||||
- `validation_sql/SQL_VALIDATION_PUMP_FUN_0_7_54.sql`.
|
||||
|
||||
Requêtes minimales attendues :
|
||||
|
||||
1. coverage `pump_fun` ;
|
||||
2. instruction observations `pump_fun` ;
|
||||
3. decoded events `pump_fun` sans coverage ;
|
||||
4. fallback upstream `pump_fun` résiduel ;
|
||||
5. successful non-materialized events sans skip reason ;
|
||||
6. failed tx materialization safety ;
|
||||
7. multi-target materialization safety ;
|
||||
8. materialization summary ;
|
||||
9. comparaison entre `k_sol_instruction_observations` et `k_sol_dex_event_coverage_entries` ;
|
||||
10. global watchlist après replay.
|
||||
|
||||
## 9. Invariants de validation
|
||||
|
||||
Après correction, viser :
|
||||
|
||||
- pas de `pump_fun` decoded event local sans coverage ;
|
||||
- pas de fallback `upstream_git` résiduel pour les entrées `pump_fun` couvertes localement ;
|
||||
- pas de materialized business event sur failed transaction ;
|
||||
- pas de multi-target incohérent ;
|
||||
- tous les events/instructions observés ont :
|
||||
- un decoder local,
|
||||
- ou un statut audit-only,
|
||||
- ou un skip reason explicite,
|
||||
- ou une justification documentée s’ils restent upstream-only.
|
||||
|
||||
## 10. Documentation à mettre à jour
|
||||
|
||||
À la fin de la tranche, mettre à jour :
|
||||
|
||||
- `CHANGELOG.md` : une ligne ;
|
||||
- `README.md` : état courant, nouvelle version, validation ;
|
||||
- `ROADMAP.md` : phasage et clôture/état de `pump_fun`, puis annonce de `pump_fees` en version suivante ;
|
||||
- `docs/DEX_DECODER_MATRIX.md` ;
|
||||
- `docs/DEX_EVENT_COVERAGE_MATRIX.md` ;
|
||||
- éventuellement un rapport :
|
||||
- `docs/reports/PUMP_FUN_EVENT_COVERAGE_REPORT.md`.
|
||||
|
||||
Ne pas gonfler les docs inutilement : noter les faits validés, les limites, et les prochaines tranches.
|
||||
|
||||
## 11. Format de livraison attendu
|
||||
|
||||
Ne pas fournir une archive complète du workspace sauf demande explicite.
|
||||
|
||||
Fournir un delta zip contenant uniquement les fichiers modifiés/ajoutés.
|
||||
|
||||
Nom recommandé :
|
||||
|
||||
`khadhroony-bobobot-v0.7.54-pump_fun-delta-N-files.zip`
|
||||
|
||||
Chaque réponse de livraison doit inclure :
|
||||
|
||||
- résumé des changements ;
|
||||
- liste exacte des fichiers modifiés ;
|
||||
- commandes à lancer :
|
||||
- `cargo fmt`
|
||||
- `cargo test -p kb_lib`
|
||||
- `cargo clippy -p kb_lib --all-targets -- -D warnings`
|
||||
- replay recommandé ;
|
||||
- SQL à exécuter ;
|
||||
- ce qui est attendu dans les résultats.
|
||||
|
||||
## 12. Priorités si plusieurs gaps apparaissent
|
||||
|
||||
Ordre de priorité :
|
||||
|
||||
1. `pump_fun` ;
|
||||
2. `pump_fees` seulement si strictement nécessaire pour comprendre un flux `pump_fun` ;
|
||||
3. ne pas traiter Meteora dans cette version ;
|
||||
4. ne pas rouvrir Raydium sauf régression démontrée ;
|
||||
5. ne pas ouvrir Jupiter/dFlow/onchain_labs dans cette tranche sauf pour les classer en backlog.
|
||||
|
||||
## 13. Première tâche demandée
|
||||
|
||||
Commencer par analyser l’archive fournie :
|
||||
|
||||
1. identifier les fichiers existants liés à `pump_fun`, `pump_fees`, upstream registry, coverage, materialization ;
|
||||
2. chercher dans `idls/**` s’il existe une IDL Solscan liée à `pump_fun` ;
|
||||
3. produire un état des lieux court :
|
||||
- entrées upstream disponibles ;
|
||||
- entrées observées dans SQL/logs fournis ;
|
||||
- fichiers à modifier ;
|
||||
- hypothèse de classification par entry ;
|
||||
- SQL initial de backfill/validation ;
|
||||
4. proposer puis produire le premier delta minimal.
|
||||
128
docs/reports/DEX_COVERAGE_GLOBAL_WATCHLIST_0_7_53.md
Normal file
128
docs/reports/DEX_COVERAGE_GLOBAL_WATCHLIST_0_7_53.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 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
|
||||
```
|
||||
166
docs/reports/PUMP_SWAP_EVENT_COVERAGE_REPORT.md
Normal file
166
docs/reports/PUMP_SWAP_EVENT_COVERAGE_REPORT.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# 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 d’instruction 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 l’instruction 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 d’instruction (`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 d’amount explicitement prouvée.
|
||||
- Les transactions failed restent decoded-only via l’actionability `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 d’anomalies 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 l’invariant 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 l’attribution 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 l’IDL. `set_reserved_fee_recipient` n’est 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 à l’ordre 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 l’instruction ;
|
||||
- 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`.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"version":"0.0.0","name":"add_decimals","instructions":[{"name":"initializeWrapper","accounts":[{"name":"wrapper","isMut":true,"isSigner":false},{"name":"wrapperUnderlyingTokens","isMut":false,"isSigner":false},{"name":"underlyingMint","isMut":false,"isSigner":false},{"name":"wrapperMint","isMut":false,"isSigner":false},{"name":"payer","isMut":false,"isSigner":true},{"name":"rent","isMut":false,"isSigner":false},{"name":"systemProgram","isMut":false,"isSigner":false}],"args":[{"name":"nonce","type":"u8"}]},{"name":"deposit","accounts":[{"name":"wrapper","isMut":false,"isSigner":false},{"name":"wrapperMint","isMut":true,"isSigner":false},{"name":"wrapperUnderlyingTokens","isMut":true,"isSigner":false},{"name":"owner","isMut":false,"isSigner":true},{"name":"userUnderlyingTokens","isMut":true,"isSigner":false},{"name":"userWrappedTokens","isMut":true,"isSigner":false},{"name":"tokenProgram","isMut":false,"isSigner":false}],"args":[{"name":"depositAmount","type":"u64"}]},{"name":"withdraw","accounts":[{"name":"wrapper","isMut":false,"isSigner":false},{"name":"wrapperMint","isMut":true,"isSigner":false},{"name":"wrapperUnderlyingTokens","isMut":true,"isSigner":false},{"name":"owner","isMut":false,"isSigner":true},{"name":"userUnderlyingTokens","isMut":true,"isSigner":false},{"name":"userWrappedTokens","isMut":true,"isSigner":false},{"name":"tokenProgram","isMut":false,"isSigner":false}],"args":[{"name":"maxBurnAmount","type":"u64"}]}],"accounts":[{"name":"WrappedToken","type":{"kind":"struct","fields":[{"name":"decimals","type":"u8"},{"name":"multiplier","type":"u64"},{"name":"wrapperUnderlyingMint","type":"publicKey"},{"name":"wrapperUnderlyingTokens","type":"publicKey"},{"name":"wrapperMint","type":"publicKey"}]}}],"events":[{"name":"InitEvent","fields":[{"name":"payer","type":"publicKey","index":false},{"name":"decimals","type":"u8","index":false},{"name":"multiplier","type":"u64","index":false},{"name":"wrapperUnderlyingMint","type":"publicKey","index":false},{"name":"wrapperUnderlyingTokens","type":"publicKey","index":false},{"name":"wrapperMint","type":"publicKey","index":false}]},{"name":"DepositEvent","fields":[{"name":"owner","type":"publicKey","index":false},{"name":"underlyingMint","type":"publicKey","index":false},{"name":"wrappedMint","type":"publicKey","index":false},{"name":"depositAmount","type":"u64","index":false},{"name":"mintAmount","type":"u64","index":false}]},{"name":"WithdrawEvent","fields":[{"name":"owner","type":"publicKey","index":false},{"name":"underlyingMint","type":"publicKey","index":false},{"name":"wrappedMint","type":"publicKey","index":false},{"name":"withdrawAmount","type":"u64","index":false},{"name":"burnAmount","type":"u64","index":false},{"name":"dustAmount","type":"u64","index":false}]}],"errors":[{"code":300,"name":"InitNonEmptyAccount","msg":"Wrapper underlying tokens account must be empty."},{"code":301,"name":"InitWrapperSupplyNonZero","msg":"Supply of the wrapper mint is non-zero"},{"code":302,"name":"InitWrapperUnderlyingOwnerMismatch","msg":"Owner of the wrapper underlying tokens account must be the wrapper"},{"code":303,"name":"InitWrapperUnderlyingMintMismatch","msg":"Underlying mint does not match underlying tokens account mint"},{"code":304,"name":"InitMintAuthorityMismatch","msg":"Mint authority mismatch"},{"code":305,"name":"InitMultiplierOverflow","msg":"Initial decimals too high"},{"code":306,"name":"InitWrapperDecimalsTooLow","msg":"The number of target decimals must be greater than or equal to the underlying asset's decimals."},{"code":307,"name":"MintAmountOverflow","msg":"Mint amount overflow. This error happens when the token cannot support this many decimals added to the token."},{"code":308,"name":"InvalidBurnAmount","msg":"Failed to convert burn amount from withdraw amount."},{"code":309,"name":"InvalidWithdrawAmount","msg":"Failed to convert withdraw amount from wrapped amount."},{"code":310,"name":"InsufficientUnderlyingBalance","msg":"User does not have enough underlying tokens"},{"code":311,"name":"InsufficientWrappedBalance","msg":"User does not have enough wrapped tokens"},{"code":312,"name":"ZeroAmount","msg":"Cannot send zero tokens"},{"code":313,"name":"UnknownAction","msg":"Unknown router action"}]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "kb-demo-app",
|
||||
"private": true,
|
||||
"version": "0.7.52",
|
||||
"version": "0.7.53",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "kb-demo-app",
|
||||
"version": "0.7.52",
|
||||
"version": "0.7.53",
|
||||
"identifier": "com.sasedev.kb-demo-app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
@@ -66,6 +66,7 @@ pub use pump_fun::PumpFunDecodedEvent;
|
||||
pub use pump_fun::PumpFunDecoder;
|
||||
pub use pump_fun::PumpFunTradeDecoded;
|
||||
pub use pump_swap::PumpSwapDecodedEvent;
|
||||
pub use pump_swap::PumpSwapInstructionDecoded;
|
||||
pub use pump_swap::PumpSwapDecoder;
|
||||
pub use pump_swap::PumpSwapTradeDecoded;
|
||||
pub use raydium_amm_v4::RaydiumAmmV4DecodedEvent;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -82,7 +82,8 @@ impl DexDecodeService {
|
||||
}
|
||||
let append_result = append_persisted_events_result(
|
||||
&mut persisted,
|
||||
self.decode_and_persist_raydium_stable_swap_events(&transaction, &instructions).await,
|
||||
self.decode_and_persist_raydium_stable_swap_events(&transaction, &instructions)
|
||||
.await,
|
||||
);
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
@@ -1679,6 +1680,17 @@ impl DexDecodeService {
|
||||
)
|
||||
.await;
|
||||
},
|
||||
crate::PumpSwapDecodedEvent::BuyExactQuoteInTrade(event) => {
|
||||
return self
|
||||
.persist_pump_swap_trade_event(
|
||||
transaction,
|
||||
event,
|
||||
"pump_swap.buy_exact_quote_in",
|
||||
"signal.dex.pump_swap.buy_exact_quote_in",
|
||||
"dex.pump_swap.buy_exact_quote_in",
|
||||
)
|
||||
.await;
|
||||
},
|
||||
crate::PumpSwapDecodedEvent::SellTrade(event) => {
|
||||
return self
|
||||
.persist_pump_swap_trade_event(
|
||||
@@ -1690,9 +1702,35 @@ impl DexDecodeService {
|
||||
)
|
||||
.await;
|
||||
},
|
||||
crate::PumpSwapDecodedEvent::Instruction(event) => {
|
||||
return self.persist_pump_swap_instruction_event(transaction, event).await;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn persist_pump_swap_instruction_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
event: &crate::PumpSwapInstructionDecoded,
|
||||
) -> Result<crate::DexDecodedEventDto, crate::Error> {
|
||||
return self
|
||||
.materialize_named_dex_event(
|
||||
transaction,
|
||||
event.transaction_id,
|
||||
event.instruction_id,
|
||||
"pump_swap",
|
||||
event.program_id.clone(),
|
||||
event.event_kind.as_str(),
|
||||
event.pool_account.clone(),
|
||||
None,
|
||||
event.token_a_mint.clone(),
|
||||
event.token_b_mint.clone(),
|
||||
event.lp_mint.clone(),
|
||||
event.payload_json.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn persist_pump_swap_trade_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
@@ -1781,18 +1819,16 @@ impl DexDecodeService {
|
||||
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_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 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),
|
||||
@@ -3686,7 +3722,10 @@ fn insert_raydium_mapped_amounts(
|
||||
);
|
||||
}
|
||||
if let Some(open_time) = read_u64_le_from_bytes(data, 2) {
|
||||
object.insert("openTime".to_string(), serde_json::Value::String(open_time.to_string()));
|
||||
object.insert(
|
||||
"openTime".to_string(),
|
||||
serde_json::Value::String(open_time.to_string()),
|
||||
);
|
||||
}
|
||||
},
|
||||
RaydiumMappedNonTradeAmountLayout::AmmV4Initialize2 => {
|
||||
@@ -3697,7 +3736,10 @@ fn insert_raydium_mapped_amounts(
|
||||
);
|
||||
}
|
||||
if let Some(open_time) = read_u64_le_from_bytes(data, 2) {
|
||||
object.insert("openTime".to_string(), serde_json::Value::String(open_time.to_string()));
|
||||
object.insert(
|
||||
"openTime".to_string(),
|
||||
serde_json::Value::String(open_time.to_string()),
|
||||
);
|
||||
}
|
||||
if let Some(init_pc_amount) = read_u64_le_from_bytes(data, 10) {
|
||||
object.insert(
|
||||
@@ -3762,7 +3804,10 @@ fn insert_raydium_mapped_amounts(
|
||||
);
|
||||
}
|
||||
if let Some(base_side) = read_u64_le_from_bytes(data, 17) {
|
||||
object.insert("baseSide".to_string(), serde_json::Value::String(base_side.to_string()));
|
||||
object.insert(
|
||||
"baseSide".to_string(),
|
||||
serde_json::Value::String(base_side.to_string()),
|
||||
);
|
||||
}
|
||||
if let Some(other_amount_min) = read_u64_le_from_bytes(data, 25) {
|
||||
object.insert(
|
||||
@@ -3773,8 +3818,14 @@ fn insert_raydium_mapped_amounts(
|
||||
},
|
||||
RaydiumMappedNonTradeAmountLayout::AmmV4Withdraw => {
|
||||
if let Some(lp_amount) = read_u64_le_from_bytes(data, 1) {
|
||||
object.insert("lpAmountRaw".to_string(), serde_json::Value::String(lp_amount.to_string()));
|
||||
object.insert("liquidity".to_string(), serde_json::Value::String(lp_amount.to_string()));
|
||||
object.insert(
|
||||
"lpAmountRaw".to_string(),
|
||||
serde_json::Value::String(lp_amount.to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"liquidity".to_string(),
|
||||
serde_json::Value::String(lp_amount.to_string()),
|
||||
);
|
||||
}
|
||||
if let Some(min_coin_amount) = read_u64_le_from_bytes(data, 9) {
|
||||
object.insert(
|
||||
@@ -3797,7 +3848,10 @@ fn insert_raydium_mapped_amounts(
|
||||
);
|
||||
}
|
||||
if let Some(value) = read_u64_le_from_bytes(data, 2) {
|
||||
object.insert("configValue".to_string(), serde_json::Value::String(value.to_string()));
|
||||
object.insert(
|
||||
"configValue".to_string(),
|
||||
serde_json::Value::String(value.to_string()),
|
||||
);
|
||||
}
|
||||
if let Some(last_order_denominator) = read_u64_le_from_bytes(data, 10) {
|
||||
object.insert(
|
||||
@@ -3808,7 +3862,8 @@ fn insert_raydium_mapped_amounts(
|
||||
},
|
||||
RaydiumMappedNonTradeAmountLayout::AmmV4WithdrawSrm => {
|
||||
if let Some(amount) = read_u64_le_from_bytes(data, 1) {
|
||||
object.insert("amountRaw".to_string(), serde_json::Value::String(amount.to_string()));
|
||||
object
|
||||
.insert("amountRaw".to_string(), serde_json::Value::String(amount.to_string()));
|
||||
}
|
||||
},
|
||||
RaydiumMappedNonTradeAmountLayout::AmmV4PreInitialize => {
|
||||
@@ -3833,10 +3888,16 @@ fn insert_raydium_mapped_amounts(
|
||||
);
|
||||
}
|
||||
if let Some(amount_in) = read_u64_le_from_bytes(data, 2) {
|
||||
object.insert("amountIn".to_string(), serde_json::Value::String(amount_in.to_string()));
|
||||
object.insert(
|
||||
"amountIn".to_string(),
|
||||
serde_json::Value::String(amount_in.to_string()),
|
||||
);
|
||||
}
|
||||
if let Some(amount_out) = read_u64_le_from_bytes(data, 10) {
|
||||
object.insert("amountOutOrMinimumAmountOut".to_string(), serde_json::Value::String(amount_out.to_string()));
|
||||
object.insert(
|
||||
"amountOutOrMinimumAmountOut".to_string(),
|
||||
serde_json::Value::String(amount_out.to_string()),
|
||||
);
|
||||
}
|
||||
},
|
||||
RaydiumMappedNonTradeAmountLayout::AmmV4AdminCancelOrders => {
|
||||
@@ -4078,7 +4139,8 @@ fn build_meteora_instruction_audit_payload(
|
||||
};
|
||||
let data_base58 = parse_instruction_data_base58(instruction.data_json.as_deref());
|
||||
let data_bytes = instruction_data_bytes_from_base58(data_base58.as_deref());
|
||||
let discriminator_hex = raydium_instruction_discriminator_hex(protocol_name, data_bytes.as_deref(), 0);
|
||||
let discriminator_hex =
|
||||
raydium_instruction_discriminator_hex(protocol_name, data_bytes.as_deref(), 0);
|
||||
let anchor_self_cpi_log =
|
||||
discriminator_hex.as_deref() == Some(METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX);
|
||||
let anchor_event_discriminator_hex = if anchor_self_cpi_log {
|
||||
@@ -4617,7 +4679,8 @@ fn build_raydium_instruction_audit_payload(
|
||||
};
|
||||
let data_base58 = parse_instruction_data_base58(instruction.data_json.as_deref());
|
||||
let data_bytes = instruction_data_bytes_from_base58(data_base58.as_deref());
|
||||
let discriminator_hex = raydium_instruction_discriminator_hex(protocol_name, data_bytes.as_deref(), 0);
|
||||
let discriminator_hex =
|
||||
raydium_instruction_discriminator_hex(protocol_name, data_bytes.as_deref(), 0);
|
||||
let anchor_self_cpi_log =
|
||||
discriminator_hex.as_deref() == Some(METEORA_ANCHOR_SELF_CPI_LOG_SELECTOR_HEX);
|
||||
let anchor_event_discriminator_hex = if anchor_self_cpi_log {
|
||||
@@ -5266,6 +5329,8 @@ fn prepare_pump_swap_trade_payload_for_classification(
|
||||
};
|
||||
if event.pool_account.is_some() && event.token_a_mint.is_some() && event.token_b_mint.is_some()
|
||||
{
|
||||
object.insert("tradeCandidate".to_string(), serde_json::Value::Bool(true));
|
||||
object.insert("candleCandidate".to_string(), serde_json::Value::Bool(true));
|
||||
return serde_json::Value::Object(object);
|
||||
}
|
||||
object.insert("tradeCandidate".to_string(), serde_json::Value::Bool(false));
|
||||
|
||||
@@ -127,6 +127,14 @@ pub(crate) fn dex_detection_route(
|
||||
}
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::PumpSwapTrade);
|
||||
},
|
||||
("pump_swap", "pump_swap.buy_exact_quote_in") => {
|
||||
if crate::dex_detection_route::is_incomplete_pump_swap_decoded_event(decoded_event) {
|
||||
return Some(
|
||||
crate::dex_detection_route::DexDetectionRoute::SkipIncompletePumpSwapTrade,
|
||||
);
|
||||
}
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::PumpSwapTrade);
|
||||
},
|
||||
("pump_swap", "pump_swap.sell") => {
|
||||
if crate::dex_detection_route::is_incomplete_pump_swap_decoded_event(decoded_event) {
|
||||
return Some(
|
||||
@@ -301,6 +309,47 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn pump_swap_buy_exact_quote_in_routes_to_pool_detection_when_complete() {
|
||||
let event = make_decoded_event(
|
||||
"pump_swap",
|
||||
"pump_swap.buy_exact_quote_in",
|
||||
Some("PumpSwapPool111"),
|
||||
Some("TokenA111"),
|
||||
Some("TokenB111"),
|
||||
);
|
||||
let route_option = crate::dex_detection_route::dex_detection_route(&event);
|
||||
let route = match route_option {
|
||||
Some(route) => route,
|
||||
None => panic!("route must be selected"),
|
||||
};
|
||||
assert_eq!(route, crate::dex_detection_route::DexDetectionRoute::PumpSwapTrade);
|
||||
assert!(crate::dex_detection_route::dex_detection_route_requires_full_pool_context(
|
||||
route
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pump_swap_buy_exact_quote_in_incomplete_route_is_skipped() {
|
||||
let event = make_decoded_event(
|
||||
"pump_swap",
|
||||
"pump_swap.buy_exact_quote_in",
|
||||
Some("PumpSwapPool111"),
|
||||
Some("TokenA111"),
|
||||
None,
|
||||
);
|
||||
let route_option = crate::dex_detection_route::dex_detection_route(&event);
|
||||
let route = match route_option {
|
||||
Some(route) => route,
|
||||
None => panic!("route must be selected"),
|
||||
};
|
||||
assert_eq!(
|
||||
route,
|
||||
crate::dex_detection_route::DexDetectionRoute::SkipIncompletePumpSwapTrade
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pump_fun_create_token_route_does_not_require_full_pool_context() {
|
||||
let event = make_decoded_event(
|
||||
|
||||
@@ -329,6 +329,12 @@ pub fn is_dex_trade_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.ends_with(".sell") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".buy_exact") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".sell_exact") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.ends_with(".swap") {
|
||||
return true;
|
||||
}
|
||||
@@ -484,6 +490,12 @@ pub fn is_dex_fee_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.contains("collect_creator_fee") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("collect_coin_creator_fee") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("transfer_creator_fees") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("collect_protocol_fee") {
|
||||
return true;
|
||||
}
|
||||
@@ -519,6 +531,18 @@ pub fn is_dex_reward_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.contains("emission") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("incentive") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("toggle_cashback_enabled") {
|
||||
return false;
|
||||
}
|
||||
if event_kind.contains("cashback") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("volume_accumulator") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -657,6 +681,9 @@ pub fn is_dex_migration_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.contains(".migrate_to_open_book") {
|
||||
return false;
|
||||
}
|
||||
if event_kind.contains(".migrate_pool_coin_creator") {
|
||||
return false;
|
||||
}
|
||||
if event_kind.contains(".migrate") {
|
||||
return true;
|
||||
}
|
||||
@@ -759,6 +786,9 @@ pub fn is_dex_admin_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.contains(".migrate_to_open_book") {
|
||||
return false;
|
||||
}
|
||||
if event_kind.contains(".migrate_pool_coin_creator") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".close_platform_global_access") {
|
||||
return true;
|
||||
}
|
||||
@@ -789,6 +819,15 @@ pub fn is_dex_admin_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.contains("set_") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("toggle_") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".disable") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".extend_account") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("update_") {
|
||||
return true;
|
||||
}
|
||||
@@ -1154,6 +1193,19 @@ mod tests {
|
||||
super::classify_dex_event_category_code("raydium_clmm.set_reward_params"),
|
||||
"reward"
|
||||
);
|
||||
assert_eq!(
|
||||
super::classify_dex_event_category_code("pump_swap.toggle_cashback_enabled"),
|
||||
"admin"
|
||||
);
|
||||
assert!(!super::is_dex_reward_event_kind("pump_swap.toggle_cashback_enabled"));
|
||||
assert!(super::is_dex_admin_event_kind("pump_swap.toggle_cashback_enabled"));
|
||||
assert_eq!(
|
||||
super::classify_dex_event_category_code("pump_swap.migrate_pool_coin_creator"),
|
||||
"admin"
|
||||
);
|
||||
assert!(!super::is_dex_pool_lifecycle_event_kind(
|
||||
"pump_swap.migrate_pool_coin_creator"
|
||||
));
|
||||
assert_eq!(
|
||||
super::classify_dex_event_category_code("raydium_clmm.increase_liquidity_v2"),
|
||||
"liquidity"
|
||||
|
||||
@@ -89,6 +89,16 @@ impl DexEventCoverageService {
|
||||
Ok(sync_counts) => sync_counts,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let cleanup_result =
|
||||
self.cleanup_deprecated_pump_swap_observed_unknown_rows(&decoder_code).await;
|
||||
if let Err(error) = cleanup_result {
|
||||
return Err(error);
|
||||
}
|
||||
let duplicate_cleanup_result =
|
||||
self.cleanup_duplicate_pump_swap_logical_coverage_rows(&decoder_code).await;
|
||||
if let Err(error) = duplicate_cleanup_result {
|
||||
return Err(error);
|
||||
}
|
||||
let refreshed_entry_count = match &decoder_code {
|
||||
Some(decoder_code) => {
|
||||
let refresh_result =
|
||||
@@ -139,6 +149,16 @@ impl DexEventCoverageService {
|
||||
Ok(sync_counts) => sync_counts,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let cleanup_result =
|
||||
self.cleanup_deprecated_pump_swap_observed_unknown_rows(&decoder_code).await;
|
||||
if let Err(error) = cleanup_result {
|
||||
return Err(error);
|
||||
}
|
||||
let duplicate_cleanup_result =
|
||||
self.cleanup_duplicate_pump_swap_logical_coverage_rows(&decoder_code).await;
|
||||
if let Err(error) = duplicate_cleanup_result {
|
||||
return Err(error);
|
||||
}
|
||||
let refreshed_entry_count = match &decoder_code {
|
||||
Some(decoder_code) => {
|
||||
let refresh_result =
|
||||
@@ -178,6 +198,86 @@ impl DexEventCoverageService {
|
||||
summaries,
|
||||
});
|
||||
}
|
||||
|
||||
async fn cleanup_deprecated_pump_swap_observed_unknown_rows(
|
||||
&self,
|
||||
decoder_code: &std::option::Option<std::string::String>,
|
||||
) -> Result<u64, crate::Error> {
|
||||
if let Some(decoder_code) = decoder_code {
|
||||
if decoder_code != "pump_swap" {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
match self.database.connection() {
|
||||
crate::DatabaseConnection::Sqlite(pool) => {
|
||||
let query_result = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM k_sol_dex_event_coverage_entries
|
||||
WHERE decoder_code = 'pump_swap'
|
||||
AND (
|
||||
entry_name LIKE 'observed_unknown_%'
|
||||
OR local_event_kind LIKE 'pump_swap.observed_unknown_%'
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.execute(pool)
|
||||
.await;
|
||||
match query_result {
|
||||
Ok(query_result) => return Ok(query_result.rows_affected()),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot delete deprecated PumpSwap observed_unknown coverage rows on sqlite: {}",
|
||||
error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn cleanup_duplicate_pump_swap_logical_coverage_rows(
|
||||
&self,
|
||||
decoder_code: &std::option::Option<std::string::String>,
|
||||
) -> Result<u64, crate::Error> {
|
||||
if let Some(decoder_code) = decoder_code {
|
||||
if decoder_code != "pump_swap" {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
match self.database.connection() {
|
||||
crate::DatabaseConnection::Sqlite(pool) => {
|
||||
let query_result = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM k_sol_dex_event_coverage_entries
|
||||
WHERE decoder_code = 'pump_swap'
|
||||
AND id NOT IN (
|
||||
SELECT MIN(id)
|
||||
FROM k_sol_dex_event_coverage_entries
|
||||
WHERE decoder_code = 'pump_swap'
|
||||
GROUP BY
|
||||
decoder_code,
|
||||
COALESCE(program_id, ''),
|
||||
entry_kind,
|
||||
entry_name,
|
||||
COALESCE(discriminator_hex, ''),
|
||||
COALESCE(local_event_kind, '')
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.execute(pool)
|
||||
.await;
|
||||
match query_result {
|
||||
Ok(query_result) => return Ok(query_result.rows_affected()),
|
||||
Err(error) => {
|
||||
return Err(crate::Error::Db(format!(
|
||||
"cannot delete duplicate PumpSwap logical coverage rows on sqlite: {}",
|
||||
error
|
||||
)));
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_coverage_entry_from_upstream(
|
||||
@@ -215,6 +315,9 @@ fn infer_expected_db_target_for_entry(
|
||||
event_family: std::option::Option<&str>,
|
||||
entry_kind: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if decoder_code == "pump_swap" {
|
||||
return infer_pump_swap_expected_db_target(entry_name, entry_kind);
|
||||
}
|
||||
if decoder_code == "raydium_cpmm"
|
||||
&& (entry_name == "swap_event" || entry_name == "anchor_idl_instruction")
|
||||
{
|
||||
@@ -421,11 +524,201 @@ fn infer_expected_db_target(
|
||||
return Some(target.to_string());
|
||||
}
|
||||
|
||||
fn infer_pump_swap_expected_db_target(
|
||||
entry_name: &str,
|
||||
entry_kind: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if entry_kind == crate::ENTRY_KIND_PROGRAM {
|
||||
return None;
|
||||
}
|
||||
if entry_name == "buy" || entry_name == "sell" || entry_name == "buy_exact_quote_in" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_TRADE_EVENTS.to_string());
|
||||
}
|
||||
if entry_name.starts_with("observed_unknown_") {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string());
|
||||
}
|
||||
if entry_name.ends_with("_event") && entry_name != "claim_token_incentives_event" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string());
|
||||
}
|
||||
if entry_name == "deposit"
|
||||
|| entry_name == "deposit_event"
|
||||
|| entry_name == "withdraw"
|
||||
|| entry_name == "withdraw_event"
|
||||
{
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "create_pool" || entry_name == "create_pool_event" {
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_LIFECYCLE_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "collect_coin_creator_fee"
|
||||
|| entry_name == "collect_coin_creator_fee_event"
|
||||
|| entry_name == "transfer_creator_fees_to_pump"
|
||||
|| entry_name == "transfer_creator_fees_to_pump_v2"
|
||||
{
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_FEE_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "claim_cashback"
|
||||
|| entry_name == "claim_cashback_event"
|
||||
|| entry_name == "claim_token_incentives"
|
||||
|| entry_name == "claim_token_incentives_event"
|
||||
|| entry_name == "admin_update_token_incentives"
|
||||
|| entry_name == "admin_update_token_incentives_event"
|
||||
|| entry_name == "init_user_volume_accumulator"
|
||||
|| entry_name == "init_user_volume_accumulator_event"
|
||||
|| entry_name == "sync_user_volume_accumulator"
|
||||
|| entry_name == "sync_user_volume_accumulator_event"
|
||||
|| entry_name == "close_user_volume_accumulator"
|
||||
|| entry_name == "close_user_volume_accumulator_event"
|
||||
{
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_REWARD_EVENTS.to_string());
|
||||
}
|
||||
if entry_name == "admin_set_coin_creator"
|
||||
|| entry_name == "admin_set_coin_creator_event"
|
||||
|| entry_name == "create_config"
|
||||
|| entry_name == "create_config_event"
|
||||
|| entry_name == "disable"
|
||||
|| entry_name == "disable_event"
|
||||
|| entry_name == "extend_account"
|
||||
|| entry_name == "extend_account_event"
|
||||
|| entry_name == "migrate_pool_coin_creator"
|
||||
|| entry_name == "migrate_pool_coin_creator_event"
|
||||
|| entry_name == "reserved_fee_recipients_event"
|
||||
|| entry_name == "set_bonding_curve_coin_creator_event"
|
||||
|| entry_name == "set_coin_creator"
|
||||
|| entry_name == "set_metaplex_coin_creator_event"
|
||||
|| entry_name == "set_reserved_fee_recipient"
|
||||
|| entry_name == "set_reserved_fee_recipients"
|
||||
|| entry_name == "toggle_cashback_enabled"
|
||||
|| entry_name == "toggle_mayhem_mode"
|
||||
|| entry_name == "update_admin"
|
||||
|| entry_name == "update_buyback_config"
|
||||
|| entry_name == "update_admin_event"
|
||||
|| entry_name == "update_fee_config"
|
||||
|| entry_name == "update_fee_config_event"
|
||||
{
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_ADMIN_EVENTS.to_string());
|
||||
}
|
||||
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string());
|
||||
}
|
||||
|
||||
fn infer_pump_swap_event_family(
|
||||
entry_name: &str,
|
||||
entry_kind: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if entry_kind == crate::ENTRY_KIND_PROGRAM {
|
||||
return None;
|
||||
}
|
||||
if entry_name == "buy" || entry_name == "sell" || entry_name == "buy_exact_quote_in" {
|
||||
return Some("swap".to_string());
|
||||
}
|
||||
if entry_name == "buy_event" || entry_name == "sell_event" {
|
||||
return Some("swap_event_audit".to_string());
|
||||
}
|
||||
if entry_name == "deposit" || entry_name == "deposit_event" {
|
||||
return Some("liquidity_add".to_string());
|
||||
}
|
||||
if entry_name == "withdraw" || entry_name == "withdraw_event" {
|
||||
return Some("liquidity_remove".to_string());
|
||||
}
|
||||
if entry_name == "create_pool" || entry_name == "create_pool_event" {
|
||||
return Some("pool_create".to_string());
|
||||
}
|
||||
if entry_name.starts_with("observed_unknown_") {
|
||||
return Some("observed_unknown_instruction".to_string());
|
||||
}
|
||||
if entry_name == "toggle_cashback_enabled"
|
||||
|| entry_name == "set_reserved_fee_recipient"
|
||||
|| entry_name == "set_reserved_fee_recipients"
|
||||
|| entry_name == "reserved_fee_recipients_event"
|
||||
{
|
||||
return Some("admin_config".to_string());
|
||||
}
|
||||
if entry_name.contains("creator_fee") || entry_name.contains("fee_recipient") {
|
||||
return Some("fee".to_string());
|
||||
}
|
||||
if entry_name.contains("cashback")
|
||||
|| entry_name.contains("incentive")
|
||||
|| entry_name.contains("volume_accumulator")
|
||||
{
|
||||
return Some("reward".to_string());
|
||||
}
|
||||
if entry_name.contains("config")
|
||||
|| entry_name.contains("admin")
|
||||
|| entry_name.contains("disable")
|
||||
|| entry_name.contains("toggle")
|
||||
|| entry_name.contains("coin_creator")
|
||||
|| entry_name.contains("extend_account")
|
||||
{
|
||||
return Some("admin_config".to_string());
|
||||
}
|
||||
return infer_event_family(entry_name, entry_kind);
|
||||
}
|
||||
|
||||
fn pump_swap_local_event_kind(entry_name: &str) -> std::option::Option<std::string::String> {
|
||||
if entry_name.ends_with("_event") {
|
||||
return Some(format!("pump_swap.{}", entry_name));
|
||||
}
|
||||
match entry_name {
|
||||
"admin_set_coin_creator" => return Some("pump_swap.admin_set_coin_creator".to_string()),
|
||||
"admin_update_token_incentives" => {
|
||||
return Some("pump_swap.admin_update_token_incentives".to_string());
|
||||
},
|
||||
"buy" => return Some("pump_swap.buy".to_string()),
|
||||
"buy_exact_quote_in" => return Some("pump_swap.buy_exact_quote_in".to_string()),
|
||||
"claim_cashback" => return Some("pump_swap.claim_cashback".to_string()),
|
||||
"claim_token_incentives" => return Some("pump_swap.claim_token_incentives".to_string()),
|
||||
"close_user_volume_accumulator" => {
|
||||
return Some("pump_swap.close_user_volume_accumulator".to_string());
|
||||
},
|
||||
"collect_coin_creator_fee" => {
|
||||
return Some("pump_swap.collect_coin_creator_fee".to_string());
|
||||
},
|
||||
"create_config" => return Some("pump_swap.create_config".to_string()),
|
||||
"create_pool" => return Some("pump_swap.create_pool".to_string()),
|
||||
"deposit" => return Some("pump_swap.deposit".to_string()),
|
||||
"disable" => return Some("pump_swap.disable".to_string()),
|
||||
"extend_account" => return Some("pump_swap.extend_account".to_string()),
|
||||
"init_user_volume_accumulator" => {
|
||||
return Some("pump_swap.init_user_volume_accumulator".to_string());
|
||||
},
|
||||
"migrate_pool_coin_creator" => {
|
||||
return Some("pump_swap.migrate_pool_coin_creator".to_string());
|
||||
},
|
||||
"sell" => return Some("pump_swap.sell".to_string()),
|
||||
"set_coin_creator" => return Some("pump_swap.set_coin_creator".to_string()),
|
||||
"set_reserved_fee_recipients" => {
|
||||
return Some("pump_swap.set_reserved_fee_recipients".to_string());
|
||||
},
|
||||
"sync_user_volume_accumulator" => {
|
||||
return Some("pump_swap.sync_user_volume_accumulator".to_string());
|
||||
},
|
||||
"toggle_cashback_enabled" => return Some("pump_swap.toggle_cashback_enabled".to_string()),
|
||||
"toggle_mayhem_mode" => return Some("pump_swap.toggle_mayhem_mode".to_string()),
|
||||
"transfer_creator_fees_to_pump" => {
|
||||
return Some("pump_swap.transfer_creator_fees_to_pump".to_string());
|
||||
},
|
||||
"transfer_creator_fees_to_pump_v2" => {
|
||||
return Some("pump_swap.transfer_creator_fees_to_pump_v2".to_string());
|
||||
},
|
||||
"update_admin" => return Some("pump_swap.update_admin".to_string()),
|
||||
"update_buyback_config" => return Some("pump_swap.update_buyback_config".to_string()),
|
||||
"update_fee_config" => return Some("pump_swap.update_fee_config".to_string()),
|
||||
"withdraw" => return Some("pump_swap.withdraw".to_string()),
|
||||
"set_reserved_fee_recipient" => {
|
||||
return Some("pump_swap.set_reserved_fee_recipient".to_string());
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_event_family_for_entry(
|
||||
decoder_code: &str,
|
||||
entry_name: &str,
|
||||
entry_kind: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if decoder_code == "pump_swap" {
|
||||
return infer_pump_swap_event_family(entry_name, entry_kind);
|
||||
}
|
||||
if decoder_code == "raydium_launchpad" {
|
||||
return infer_raydium_launchpad_event_family(entry_name, entry_kind);
|
||||
}
|
||||
@@ -488,7 +781,6 @@ fn infer_raydium_cpmm_event_family(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn infer_raydium_stable_swap_event_family(
|
||||
entry_name: &str,
|
||||
entry_kind: &str,
|
||||
@@ -789,7 +1081,6 @@ 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> {
|
||||
@@ -819,6 +1110,9 @@ pub(crate) fn known_local_event_kind(
|
||||
decoder_code: &str,
|
||||
entry_name: &str,
|
||||
) -> std::option::Option<std::string::String> {
|
||||
if decoder_code == "pump_swap" {
|
||||
return pump_swap_local_event_kind(entry_name);
|
||||
}
|
||||
if decoder_code == "raydium_amm_v4" {
|
||||
return raydium_amm_v4_local_event_kind(entry_name);
|
||||
}
|
||||
|
||||
@@ -319,6 +319,63 @@ fn resolve_instruction_name(
|
||||
};
|
||||
return Some(format!("raydium_launchpad.{}", layout.instruction_name));
|
||||
}
|
||||
if program_id == crate::PUMP_SWAP_PROGRAM_ID || decoder_code == Some("pump_swap") {
|
||||
let name = match discriminator_hex {
|
||||
"e445a52e51cb9a1d" => "anchor_self_cpi_log",
|
||||
"f228759149606968" => "admin_set_coin_creator",
|
||||
"d10b7357d5177ccc" => "admin_update_token_incentives",
|
||||
"66063d1201daebea" => "buy",
|
||||
"c62e1552b4d9e870" => "buy_exact_quote_in",
|
||||
"253a237ebe35e4c5" => "claim_cashback",
|
||||
"1004471ccc01281b" => "claim_token_incentives",
|
||||
"f945a4da9667548a" => "close_user_volume_accumulator",
|
||||
"a039592ab58b2b42" => "collect_coin_creator_fee",
|
||||
"c9cff3724b6f2fbd" => "create_config",
|
||||
"e992d18ecf6840bc" => "create_pool",
|
||||
"f223c68952e1f2b6" => "deposit",
|
||||
"b9adbb5ad80feee9" => "disable",
|
||||
"ea66c2cb96483ee5" => "extend_account",
|
||||
"5e06ca73ff60e8b7" => "init_user_volume_accumulator",
|
||||
"d0089f044aaf103a" => "migrate_pool_coin_creator",
|
||||
"33e685a4017f83ad" => "sell",
|
||||
"d295802dbc3a4eaf" => "set_coin_creator",
|
||||
"6faca2e87259d58e" => "set_reserved_fee_recipients",
|
||||
"561fc057a3574fee" => "sync_user_volume_accumulator",
|
||||
"7367e0ffbd5956c3" => "toggle_cashback_enabled",
|
||||
"01096fd0641fffa3" => "toggle_mayhem_mode",
|
||||
"8b348655e4e56cf1" => "transfer_creator_fees_to_pump",
|
||||
"01214eb921432c5c" => "transfer_creator_fees_to_pump_v2",
|
||||
"a1b028d53cb8b3e4" => "update_admin",
|
||||
"fbe0ab92a01a71e9" => "update_buyback_config",
|
||||
"68b867f258976b14" => "update_fee_config",
|
||||
"b712469c946da122" => "withdraw",
|
||||
"cfbdb247a77a44b4" => "set_reserved_fee_recipient",
|
||||
"2ddc5d181961ac68" => "admin_set_coin_creator_event",
|
||||
"93fa6c78f71d43de" => "admin_update_token_incentives_event",
|
||||
"67f4521f2cf57777" => "buy_event",
|
||||
"e2d6f62107f293e5" => "claim_cashback_event",
|
||||
"4facf631cd5bcee8" => "claim_token_incentives_event",
|
||||
"929fbdac925838f4" => "close_user_volume_accumulator_event",
|
||||
"e8f5c2eeeada3a59" => "collect_coin_creator_fee_event",
|
||||
"6b34598137e25116" => "create_config_event",
|
||||
"b1310cd2a076a774" => "create_pool_event",
|
||||
"78f83d531f8e6b90" => "deposit_event",
|
||||
"6bfdc14ce4ca1b68" => "disable_event",
|
||||
"6161d7905d92167c" => "extend_account_event",
|
||||
"86240d48e86582d8" => "init_user_volume_accumulator_event",
|
||||
"aadd52c793a5f72e" => "migrate_pool_coin_creator_event",
|
||||
"2bbcfa12dd4bbb5f" => "reserved_fee_recipients_event",
|
||||
"3e2f370aa503dc2a" => "sell_event",
|
||||
"f2e7eb664163bdd3" => "set_bonding_curve_coin_creator_event",
|
||||
"966bc77b7ccf66e4" => "set_metaplex_coin_creator_event",
|
||||
"c57aa77c74515bff" => "sync_user_volume_accumulator_event",
|
||||
"e198ab57f63f42ea" => "update_admin_event",
|
||||
"5a1741233ef4bcd0" => "update_fee_config_event",
|
||||
"1609851aa02c47c0" => "withdraw_event",
|
||||
_ => return None,
|
||||
};
|
||||
return Some(name.to_string());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -1183,6 +1183,8 @@ pub use dex::PumpFunTradeDecoded;
|
||||
pub use dex::PumpSwapDecodedEvent;
|
||||
/// PumpSwap decoder.
|
||||
pub use dex::PumpSwapDecoder;
|
||||
/// Decoded PumpSwap non-trade instruction event.
|
||||
pub use dex::PumpSwapInstructionDecoded;
|
||||
/// Decoded PumpSwap trade event.
|
||||
pub use dex::PumpSwapTradeDecoded;
|
||||
/// Decoded Raydium AmmV4 event.
|
||||
|
||||
@@ -109,6 +109,9 @@ impl NonTradeEventMaterializationService {
|
||||
continue;
|
||||
},
|
||||
};
|
||||
if is_anchor_event_audit_only(&payload) {
|
||||
continue;
|
||||
}
|
||||
if crate::is_dex_pool_lifecycle_event_kind(decoded_event.event_kind.as_str()) {
|
||||
let cleanup_result =
|
||||
self.delete_stale_pool_admin_event_for_lifecycle(decoded_event).await;
|
||||
@@ -1935,6 +1938,18 @@ fn extract_first_bool(
|
||||
return None;
|
||||
}
|
||||
|
||||
fn is_anchor_event_audit_only(payload: &serde_json::Value) -> bool {
|
||||
if let Some(object) = payload.as_object() {
|
||||
let flag = object.get("anchorEventAuditOnly");
|
||||
if let Some(flag) = flag {
|
||||
if flag.as_bool() == Some(true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn transaction_has_effective_error(transaction: &crate::ChainTransactionDto) -> bool {
|
||||
let err_json = match transaction.err_json.as_ref() {
|
||||
Some(err_json) => err_json.trim(),
|
||||
|
||||
@@ -47,9 +47,10 @@ impl TradeAggregationService {
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let transaction = transaction_context.transaction;
|
||||
if transaction.err_json.is_some() {
|
||||
if crate::trade_aggregation::transaction_has_effective_error(&transaction) {
|
||||
tracing::debug!(
|
||||
signature = %transaction.signature,
|
||||
err_json = ?transaction.err_json,
|
||||
"skipping trade aggregation for failed transaction"
|
||||
);
|
||||
return Ok(std::vec::Vec::new());
|
||||
@@ -199,6 +200,21 @@ impl TradeAggregationService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn transaction_has_effective_error(transaction: &crate::ChainTransactionDto) -> bool {
|
||||
let err_json = match transaction.err_json.as_ref() {
|
||||
Some(err_json) => err_json.trim(),
|
||||
None => return false,
|
||||
};
|
||||
if err_json.is_empty() {
|
||||
return false;
|
||||
}
|
||||
if err_json == "null" {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
async fn make_database() -> std::sync::Arc<crate::Database> {
|
||||
@@ -416,6 +432,51 @@ mod tests {
|
||||
assert_eq!(pair_metric.trade_count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_null_err_json_is_not_effective_error() {
|
||||
let transaction = crate::ChainTransactionDto::new(
|
||||
"sig-null-err".to_string(),
|
||||
Some(1),
|
||||
None,
|
||||
Some("test".to_string()),
|
||||
Some("0".to_string()),
|
||||
Some("null".to_string()),
|
||||
None,
|
||||
serde_json::json!({"meta":{"err":null}}).to_string(),
|
||||
);
|
||||
assert!(!super::transaction_has_effective_error(&transaction));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_empty_err_json_is_not_effective_error() {
|
||||
let transaction = crate::ChainTransactionDto::new(
|
||||
"sig-empty-err".to_string(),
|
||||
Some(1),
|
||||
None,
|
||||
Some("test".to_string()),
|
||||
Some("0".to_string()),
|
||||
Some("".to_string()),
|
||||
None,
|
||||
serde_json::json!({"meta":{"err":null}}).to_string(),
|
||||
);
|
||||
assert!(!super::transaction_has_effective_error(&transaction));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_non_null_err_json_is_effective_error() {
|
||||
let transaction = crate::ChainTransactionDto::new(
|
||||
"sig-real-err".to_string(),
|
||||
Some(1),
|
||||
None,
|
||||
Some("test".to_string()),
|
||||
Some("0".to_string()),
|
||||
Some(serde_json::json!({"InstructionError":[0,{"Custom":1}]}).to_string()),
|
||||
None,
|
||||
serde_json::json!({"meta":{"err":{"InstructionError":[0,{"Custom":1}]}}}).to_string(),
|
||||
);
|
||||
assert!(super::transaction_has_effective_error(&transaction));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn record_transaction_by_signature_skips_failed_transaction() {
|
||||
let database = make_database().await;
|
||||
|
||||
@@ -138,6 +138,14 @@ pub(crate) async fn resolve_trade_amounts(
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if input.decoded_event.event_kind == "pump_swap.buy_exact_quote_in" {
|
||||
crate::trade_amount_resolution::normalize_pump_swap_anchor_buy_exact_quote_in_amounts(
|
||||
input,
|
||||
&mut base_amount_raw,
|
||||
&mut quote_amount_raw,
|
||||
&mut resolved_trade_side,
|
||||
);
|
||||
}
|
||||
if input.decoded_event.event_kind.starts_with("raydium_launchpad.")
|
||||
&& (base_amount_raw.is_none()
|
||||
|| quote_amount_raw.is_none()
|
||||
@@ -442,7 +450,12 @@ async fn apply_pump_swap_amount_fallbacks(
|
||||
None => payload_pool_quote_token_account.as_deref(),
|
||||
};
|
||||
let (input_vault_address, output_vault_address, input_token_account, output_token_account) =
|
||||
if input.decoded_event.event_kind.ends_with(".buy") {
|
||||
if input.decoded_event.event_kind.ends_with(".buy")
|
||||
|| input
|
||||
.decoded_event
|
||||
.event_kind
|
||||
.ends_with(".buy_exact_quote_in")
|
||||
{
|
||||
(
|
||||
effective_quote_vault_address,
|
||||
effective_base_vault_address,
|
||||
@@ -1401,6 +1414,74 @@ async fn load_decoded_instruction(
|
||||
return Ok(instruction_option);
|
||||
}
|
||||
|
||||
|
||||
fn normalize_pump_swap_anchor_buy_exact_quote_in_amounts(
|
||||
input: &crate::trade_amount_resolution::TradeAmountResolutionInput<'_>,
|
||||
base_amount_raw: &mut std::option::Option<std::string::String>,
|
||||
quote_amount_raw: &mut std::option::Option<std::string::String>,
|
||||
resolved_trade_side: &mut std::option::Option<crate::SwapTradeSide>,
|
||||
) {
|
||||
let amount_source = crate::trade_amount_resolution::extract_string_by_candidate_keys(
|
||||
input.payload,
|
||||
&["amountSource", "amount_source"],
|
||||
);
|
||||
if amount_source.as_deref() != Some("pump_swap_anchor_buy_event") {
|
||||
return;
|
||||
}
|
||||
let token_a_mint = crate::trade_amount_resolution::extract_string_by_candidate_keys(
|
||||
input.payload,
|
||||
&["tokenAMint", "token_a_mint"],
|
||||
);
|
||||
let token_b_mint = crate::trade_amount_resolution::extract_string_by_candidate_keys(
|
||||
input.payload,
|
||||
&["tokenBMint", "token_b_mint"],
|
||||
);
|
||||
let token_a_mint = match token_a_mint.as_deref() {
|
||||
Some(token_a_mint) => token_a_mint,
|
||||
None => return,
|
||||
};
|
||||
let token_b_mint = match token_b_mint.as_deref() {
|
||||
Some(token_b_mint) => token_b_mint,
|
||||
None => return,
|
||||
};
|
||||
let pair_base_mint = match input.base_token_mint {
|
||||
Some(pair_base_mint) => pair_base_mint,
|
||||
None => return,
|
||||
};
|
||||
let pair_quote_mint = match input.quote_token_mint {
|
||||
Some(pair_quote_mint) => pair_quote_mint,
|
||||
None => return,
|
||||
};
|
||||
let anchor_base_amount_raw = crate::trade_amount_resolution::extract_amount_string(
|
||||
input.payload,
|
||||
&["baseAmountRaw", "baseAmountOutRaw", "base_amount_out_raw"],
|
||||
);
|
||||
let anchor_quote_amount_raw = crate::trade_amount_resolution::extract_amount_string(
|
||||
input.payload,
|
||||
&["quoteAmountRaw", "userQuoteAmountInRaw", "user_quote_amount_in_raw"],
|
||||
);
|
||||
let anchor_base_amount_raw = match anchor_base_amount_raw {
|
||||
Some(anchor_base_amount_raw) => anchor_base_amount_raw,
|
||||
None => return,
|
||||
};
|
||||
let anchor_quote_amount_raw = match anchor_quote_amount_raw {
|
||||
Some(anchor_quote_amount_raw) => anchor_quote_amount_raw,
|
||||
None => return,
|
||||
};
|
||||
if pair_base_mint == token_a_mint && pair_quote_mint == token_b_mint {
|
||||
*base_amount_raw = Some(anchor_base_amount_raw);
|
||||
*quote_amount_raw = Some(anchor_quote_amount_raw);
|
||||
*resolved_trade_side = Some(crate::SwapTradeSide::BuyBase);
|
||||
return;
|
||||
}
|
||||
if pair_base_mint == token_b_mint && pair_quote_mint == token_a_mint {
|
||||
*base_amount_raw = Some(anchor_quote_amount_raw);
|
||||
*quote_amount_raw = Some(anchor_base_amount_raw);
|
||||
*resolved_trade_side = Some(crate::SwapTradeSide::SellBase);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_amount_string(
|
||||
payload: &serde_json::Value,
|
||||
candidate_keys: &[&str],
|
||||
|
||||
@@ -23,10 +23,10 @@ pub(crate) fn extract_trade_side(
|
||||
Some("SELL") => return crate::SwapTradeSide::SellBase,
|
||||
_ => {},
|
||||
}
|
||||
if event_kind.ends_with(".buy") {
|
||||
if event_kind.ends_with(".buy") || event_kind.contains(".buy_exact") {
|
||||
return crate::SwapTradeSide::BuyBase;
|
||||
}
|
||||
if event_kind.ends_with(".sell") {
|
||||
if event_kind.ends_with(".sell") || event_kind.contains(".sell_exact") {
|
||||
return crate::SwapTradeSide::SellBase;
|
||||
}
|
||||
return crate::SwapTradeSide::Unknown;
|
||||
@@ -109,6 +109,13 @@ mod tests {
|
||||
assert_eq!(side, crate::SwapTradeSide::SellBase);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buy_exact_suffix_is_resolved_as_buy_base() {
|
||||
let payload = serde_json::json!({});
|
||||
let side = super::extract_trade_side("pump_swap.buy_exact_quote_in", &payload);
|
||||
assert_eq!(side, crate::SwapTradeSide::BuyBase);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_side_is_returned_when_no_hint_exists() {
|
||||
let payload = serde_json::json!({});
|
||||
|
||||
@@ -14,9 +14,8 @@ const UPSTREAM_GIT_ALIAS_PROGRAM_NOTES: &str = "upstream Git decoder name kept a
|
||||
|
||||
const RAYDIUM_IDL_SOURCE_REPO: &str = "raydium-io/raydium-idl";
|
||||
const MANUAL_SOLSCAN_SOURCE_REPO: &str = "manual-solscan";
|
||||
|
||||
const RAYDIUM_IDL_DISCRIMINATOR_NOTES: &str = "entry name and discriminator extracted from Raydium official IDL snapshot; not corpus-verified; no trade/candle/materialization proof";
|
||||
const MANUAL_SOLSCAN_DISCRIMINATOR_NOTES: &str = "entry name and discriminator derived from local corpus plus manual Solscan transaction-log inspection; no trade/candle/materialization proof";
|
||||
const MANUAL_SOLSCAN_DISCRIMINATOR_NOTES: &str = "entry name and discriminator derived from manual Solscan program IDL or Solscan transaction-log inspection; no trade/candle/materialization proof";
|
||||
|
||||
const fn manual_solscan_discriminator_entry(
|
||||
decoder_code: &'static str,
|
||||
@@ -10735,6 +10734,39 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
|
||||
8,
|
||||
"decoders/pump-swap-decoder/src/instructions/withdraw.rs",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"pump_swap",
|
||||
Some(crate::PUMP_SWAP_PROGRAM_ID),
|
||||
"pump",
|
||||
"amm",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"transfer_creator_fees_to_pump_v2",
|
||||
"01214eb921432c5c",
|
||||
8,
|
||||
"solscan.io/account/pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA#programIdl:transfer_creator_fees_to_pump_v2",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"pump_swap",
|
||||
Some(crate::PUMP_SWAP_PROGRAM_ID),
|
||||
"pump",
|
||||
"amm",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"update_buyback_config",
|
||||
"fbe0ab92a01a71e9",
|
||||
8,
|
||||
"solscan.io/account/pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA#programIdl:update_buyback_config",
|
||||
),
|
||||
manual_solscan_discriminator_entry(
|
||||
"pump_swap",
|
||||
Some(crate::PUMP_SWAP_PROGRAM_ID),
|
||||
"pump",
|
||||
"amm",
|
||||
crate::ENTRY_KIND_INSTRUCTION,
|
||||
"set_reserved_fee_recipient",
|
||||
"cfbdb247a77a44b4",
|
||||
8,
|
||||
"validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql#local_log_instruction_names",
|
||||
),
|
||||
upstream_git_discriminator_entry(
|
||||
"pump_swap",
|
||||
Some(crate::PUMP_SWAP_PROGRAM_ID),
|
||||
|
||||
274
validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql
Normal file
274
validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql
Normal file
@@ -0,0 +1,274 @@
|
||||
-- file: validation_sql/SQL_VALIDATION_DEX_COVERAGE_GLOBAL_0_7_53.sql
|
||||
|
||||
-- Global DEX coverage watchlist for the 0.7.53 PumpSwap closure.
|
||||
-- Run after a forced local replay when the goal is to detect:
|
||||
-- - decoded local events without coverage entries;
|
||||
-- - upstream_git fallbacks that still need a local decoder or an explicit deferral;
|
||||
-- - instruction observations not covered by k_sol_dex_event_coverage_entries;
|
||||
-- - unattributed discriminators that need program-id classification;
|
||||
-- - PumpSwap/Raydium non-regression after future backfills.
|
||||
|
||||
-- 01. Local decoded events without coverage.
|
||||
-- Expected after 0.7.53 closure: no pump_swap or validated Raydium rows.
|
||||
-- Known deferred rows at closure time: small Meteora gaps, intentionally not fixed in 0.7.53.
|
||||
SELECT
|
||||
de.protocol_name,
|
||||
de.event_kind,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(DISTINCT de.transaction_id) AS tx_count,
|
||||
MIN(tx.signature) AS sample_signature
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = de.protocol_name
|
||||
AND ce.local_event_kind = de.event_kind
|
||||
WHERE de.protocol_name <> 'upstream_git'
|
||||
AND ce.id IS NULL
|
||||
GROUP BY
|
||||
de.protocol_name,
|
||||
de.event_kind
|
||||
ORDER BY
|
||||
decoded_count DESC,
|
||||
de.protocol_name,
|
||||
de.event_kind;
|
||||
|
||||
-- 02. Upstream fallback backlog to promote or defer.
|
||||
-- This is a roadmap queue, not a local decoder error by itself.
|
||||
SELECT
|
||||
json_extract(de.payload_json, '$.upstreamDecoderCode') AS upstream_decoder_code,
|
||||
json_extract(de.payload_json, '$.upstreamEntryName') AS upstream_entry_name,
|
||||
json_extract(de.payload_json, '$.upstreamDiscriminatorHex') AS upstream_discriminator_hex,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(DISTINCT de.transaction_id) AS tx_count,
|
||||
MIN(tx.signature) AS sample_signature
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
WHERE de.protocol_name = 'upstream_git'
|
||||
AND de.event_kind = 'upstream_git.instruction_match'
|
||||
GROUP BY
|
||||
upstream_decoder_code,
|
||||
upstream_entry_name,
|
||||
upstream_discriminator_hex
|
||||
ORDER BY
|
||||
decoded_count DESC,
|
||||
upstream_decoder_code,
|
||||
upstream_entry_name;
|
||||
|
||||
-- 03. Instruction observations with decoder_code but no coverage, normalized.
|
||||
-- Handles both instruction_name='swap_base_input' and instruction_name='raydium_cpmm.swap_base_input'.
|
||||
WITH normalized_io AS (
|
||||
SELECT
|
||||
io.decoder_code,
|
||||
io.instruction_name,
|
||||
CASE
|
||||
WHEN io.decoder_code IS NOT NULL
|
||||
AND TRIM(io.decoder_code) <> ''
|
||||
AND io.instruction_name LIKE (io.decoder_code || '.%')
|
||||
THEN SUBSTR(io.instruction_name, LENGTH(io.decoder_code) + 2)
|
||||
ELSE io.instruction_name
|
||||
END AS normalized_entry_name,
|
||||
io.discriminator_hex,
|
||||
io.signature
|
||||
FROM k_sol_instruction_observations io
|
||||
WHERE io.discriminator_hex IS NOT NULL
|
||||
AND io.discriminator_hex <> ''
|
||||
AND io.discriminator_hex <> 'e445a52e51cb9a1d'
|
||||
AND io.decoder_code IS NOT NULL
|
||||
AND TRIM(io.decoder_code) <> ''
|
||||
)
|
||||
SELECT
|
||||
nio.decoder_code,
|
||||
nio.instruction_name,
|
||||
nio.normalized_entry_name,
|
||||
nio.discriminator_hex,
|
||||
COUNT(*) AS observed_count,
|
||||
COUNT(DISTINCT nio.signature) AS tx_count,
|
||||
MIN(nio.signature) AS sample_signature
|
||||
FROM normalized_io nio
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = nio.decoder_code
|
||||
AND COALESCE(ce.discriminator_hex, '') = COALESCE(nio.discriminator_hex, '')
|
||||
AND (
|
||||
ce.entry_name = nio.instruction_name
|
||||
OR ce.entry_name = nio.normalized_entry_name
|
||||
OR ce.local_event_kind = nio.instruction_name
|
||||
OR ce.local_event_kind = (nio.decoder_code || '.' || nio.normalized_entry_name)
|
||||
)
|
||||
WHERE ce.id IS NULL
|
||||
GROUP BY
|
||||
nio.decoder_code,
|
||||
nio.instruction_name,
|
||||
nio.normalized_entry_name,
|
||||
nio.discriminator_hex
|
||||
ORDER BY
|
||||
observed_count DESC,
|
||||
nio.decoder_code,
|
||||
nio.discriminator_hex;
|
||||
|
||||
-- 04. Unattributed instruction observations.
|
||||
-- Treat as classification backlog: discriminator alone is not enough; inspect sample_signature/program_id first.
|
||||
SELECT
|
||||
io.discriminator_hex,
|
||||
COUNT(*) AS observed_count,
|
||||
COUNT(DISTINCT io.signature) AS tx_count,
|
||||
MIN(io.signature) AS sample_signature
|
||||
FROM k_sol_instruction_observations io
|
||||
WHERE io.discriminator_hex IS NOT NULL
|
||||
AND io.discriminator_hex <> ''
|
||||
AND io.discriminator_hex <> 'e445a52e51cb9a1d'
|
||||
AND (
|
||||
io.decoder_code IS NULL
|
||||
OR TRIM(io.decoder_code) = ''
|
||||
)
|
||||
GROUP BY
|
||||
io.discriminator_hex
|
||||
ORDER BY
|
||||
observed_count DESC,
|
||||
io.discriminator_hex;
|
||||
|
||||
-- 05. PumpSwap local closure check.
|
||||
-- Expected result: empty.
|
||||
WITH normalized_io AS (
|
||||
SELECT
|
||||
io.decoder_code,
|
||||
io.instruction_name,
|
||||
CASE
|
||||
WHEN io.instruction_name LIKE 'pump_swap.%'
|
||||
THEN SUBSTR(io.instruction_name, LENGTH('pump_swap') + 2)
|
||||
ELSE io.instruction_name
|
||||
END AS normalized_entry_name,
|
||||
io.discriminator_hex,
|
||||
io.signature
|
||||
FROM k_sol_instruction_observations io
|
||||
WHERE io.decoder_code = 'pump_swap'
|
||||
AND io.discriminator_hex IS NOT NULL
|
||||
AND io.discriminator_hex <> ''
|
||||
AND io.discriminator_hex <> 'e445a52e51cb9a1d'
|
||||
)
|
||||
SELECT
|
||||
nio.decoder_code,
|
||||
nio.instruction_name,
|
||||
nio.normalized_entry_name,
|
||||
nio.discriminator_hex,
|
||||
COUNT(*) AS observed_count,
|
||||
COUNT(DISTINCT nio.signature) AS tx_count,
|
||||
MIN(nio.signature) AS sample_signature
|
||||
FROM normalized_io nio
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = 'pump_swap'
|
||||
AND COALESCE(ce.discriminator_hex, '') = COALESCE(nio.discriminator_hex, '')
|
||||
AND (
|
||||
ce.entry_name = nio.instruction_name
|
||||
OR ce.entry_name = nio.normalized_entry_name
|
||||
OR ce.local_event_kind = nio.instruction_name
|
||||
OR ce.local_event_kind = ('pump_swap.' || nio.normalized_entry_name)
|
||||
)
|
||||
WHERE ce.id IS NULL
|
||||
GROUP BY
|
||||
nio.decoder_code,
|
||||
nio.instruction_name,
|
||||
nio.normalized_entry_name,
|
||||
nio.discriminator_hex
|
||||
ORDER BY observed_count DESC;
|
||||
|
||||
-- 06. Raydium AMM v4 / CLMM / CPMM targeted non-regression.
|
||||
-- Expected result after 0.7.53 closure: empty.
|
||||
WITH normalized_io AS (
|
||||
SELECT
|
||||
io.decoder_code,
|
||||
io.instruction_name,
|
||||
CASE
|
||||
WHEN io.decoder_code IS NOT NULL
|
||||
AND TRIM(io.decoder_code) <> ''
|
||||
AND io.instruction_name LIKE (io.decoder_code || '.%')
|
||||
THEN SUBSTR(io.instruction_name, LENGTH(io.decoder_code) + 2)
|
||||
ELSE io.instruction_name
|
||||
END AS normalized_entry_name,
|
||||
io.discriminator_hex,
|
||||
io.signature
|
||||
FROM k_sol_instruction_observations io
|
||||
WHERE io.decoder_code IN (
|
||||
'raydium_amm_v4',
|
||||
'raydium_clmm',
|
||||
'raydium_cpmm'
|
||||
)
|
||||
AND io.discriminator_hex IS NOT NULL
|
||||
AND io.discriminator_hex <> ''
|
||||
)
|
||||
SELECT
|
||||
nio.decoder_code,
|
||||
nio.instruction_name,
|
||||
nio.normalized_entry_name,
|
||||
nio.discriminator_hex,
|
||||
COUNT(*) AS observed_count,
|
||||
COUNT(DISTINCT nio.signature) AS tx_count,
|
||||
MIN(nio.signature) AS sample_signature
|
||||
FROM normalized_io nio
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = nio.decoder_code
|
||||
AND COALESCE(ce.discriminator_hex, '') = COALESCE(nio.discriminator_hex, '')
|
||||
AND (
|
||||
ce.entry_name = nio.instruction_name
|
||||
OR ce.entry_name = nio.normalized_entry_name
|
||||
OR ce.local_event_kind = nio.instruction_name
|
||||
OR ce.local_event_kind = (nio.decoder_code || '.' || nio.normalized_entry_name)
|
||||
)
|
||||
WHERE ce.id IS NULL
|
||||
GROUP BY
|
||||
nio.decoder_code,
|
||||
nio.instruction_name,
|
||||
nio.normalized_entry_name,
|
||||
nio.discriminator_hex
|
||||
ORDER BY
|
||||
observed_count DESC,
|
||||
nio.decoder_code,
|
||||
nio.discriminator_hex;
|
||||
|
||||
-- 07. Raydium swap/trade coverage overview.
|
||||
-- This is informational. Entries with observed_count=0 are unobserved registry coverage, not failures.
|
||||
SELECT
|
||||
decoder_code,
|
||||
entry_kind,
|
||||
entry_name,
|
||||
event_family,
|
||||
local_event_kind,
|
||||
discriminator_hex,
|
||||
expected_db_target,
|
||||
proof_status,
|
||||
observed_count,
|
||||
materialized_count,
|
||||
trade_count
|
||||
FROM k_sol_dex_event_coverage_entries
|
||||
WHERE decoder_code IN (
|
||||
'raydium_amm_v4',
|
||||
'raydium_clmm',
|
||||
'raydium_cpmm',
|
||||
'raydium_stable_swap',
|
||||
'raydium_launchpad'
|
||||
)
|
||||
AND (
|
||||
event_family IN ('swap', 'swap_event_audit')
|
||||
OR expected_db_target = 'k_sol_trade_events'
|
||||
)
|
||||
ORDER BY
|
||||
decoder_code,
|
||||
entry_kind,
|
||||
entry_name,
|
||||
discriminator_hex;
|
||||
|
||||
-- 08. Upstream backlog by decoder_code.
|
||||
SELECT
|
||||
json_extract(de.payload_json, '$.upstreamDecoderCode') AS upstream_decoder_code,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(DISTINCT de.transaction_id) AS tx_count,
|
||||
COUNT(DISTINCT json_extract(de.payload_json, '$.upstreamEntryName')) AS distinct_entry_count,
|
||||
MIN(tx.signature) AS sample_signature
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
WHERE de.protocol_name = 'upstream_git'
|
||||
AND de.event_kind = 'upstream_git.instruction_match'
|
||||
GROUP BY upstream_decoder_code
|
||||
ORDER BY decoded_count DESC, upstream_decoder_code;
|
||||
325
validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql
Normal file
325
validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql
Normal file
@@ -0,0 +1,325 @@
|
||||
-- file: validation_sql/SQL_VALIDATION_PUMP_SWAP_0_7_53.sql
|
||||
|
||||
-- 0.7.53 pump_swap validation checklist.
|
||||
-- Run on a dedicated fresh SQLite database after corpus construction and replay with:
|
||||
-- skipDexDecode=no, forceDexDecode=yes, deferInstructionObservations=yes.
|
||||
|
||||
-- 01. Coverage pump_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 = 'pump_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 = 'pump_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 = 'pump_swap'
|
||||
AND event_kind = 'pump_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') = 'pump_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 = 'pump_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 = 'pump_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 = 'pump_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 = 'pump_swap'
|
||||
AND ce.local_event_kind = de.event_kind
|
||||
WHERE de.protocol_name = 'pump_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 re.id) AS reward_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 re.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_reward_events re
|
||||
ON re.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 = 'pump_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_reward_events re
|
||||
ON re.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 = 'pump_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 re.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 re.id) AS reward_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_reward_events re
|
||||
ON re.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 = 'pump_swap'
|
||||
GROUP BY de.event_kind
|
||||
ORDER BY de.event_kind;
|
||||
|
||||
|
||||
|
||||
-- 11. PumpSwap local instruction discriminator coverage.
|
||||
-- Expected result after Solscan IDL/log-name promotion: covered rows only, except the Anchor self-CPI log carrier.
|
||||
-- Rows tagged coverage_gap must be promoted to an explicit local decoder status or excluded with proof.
|
||||
SELECT
|
||||
io.instruction_name,
|
||||
io.discriminator_hex,
|
||||
COUNT(*) AS observed_count,
|
||||
COUNT(DISTINCT io.signature) AS tx_count,
|
||||
CASE
|
||||
WHEN io.discriminator_hex = 'e445a52e51cb9a1d' THEN 'technical_anchor_self_cpi_log'
|
||||
WHEN ce.id IS NULL THEN 'coverage_gap'
|
||||
ELSE 'covered'
|
||||
END AS observation_coverage_status,
|
||||
ce.local_event_kind,
|
||||
ce.expected_db_target,
|
||||
ce.proof_status
|
||||
FROM k_sol_instruction_observations io
|
||||
LEFT JOIN k_sol_dex_event_coverage_entries ce
|
||||
ON ce.decoder_code = 'pump_swap'
|
||||
AND ce.discriminator_hex = io.discriminator_hex
|
||||
AND (
|
||||
ce.entry_name = io.instruction_name
|
||||
OR ce.local_event_kind = ('pump_swap.' || io.instruction_name)
|
||||
)
|
||||
WHERE io.decoder_code = 'pump_swap'
|
||||
GROUP BY
|
||||
io.instruction_name,
|
||||
io.discriminator_hex,
|
||||
observation_coverage_status,
|
||||
ce.local_event_kind,
|
||||
ce.expected_db_target,
|
||||
ce.proof_status
|
||||
ORDER BY observed_count DESC, io.instruction_name, io.discriminator_hex;
|
||||
|
||||
-- 12. PumpSwap successful trade candidates without materialized trade.
|
||||
-- Expected result: empty unless skipTradeReason explicitly documents why amounts/direction are incomplete.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
json_extract(de.payload_json, '$.skipTradeReason') AS skip_trade_reason,
|
||||
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 = 'pump_swap'
|
||||
AND de.event_kind IN (
|
||||
'pump_swap.buy',
|
||||
'pump_swap.sell',
|
||||
'pump_swap.buy_exact_quote_in'
|
||||
)
|
||||
AND (
|
||||
tx.err_json IS NULL
|
||||
OR tx.err_json = ''
|
||||
OR tx.err_json = 'null'
|
||||
)
|
||||
GROUP BY de.event_kind, skip_trade_reason
|
||||
HAVING COUNT(te.id) = 0
|
||||
AND COALESCE(TRIM(skip_trade_reason), '') = ''
|
||||
ORDER BY decoded_count DESC, de.event_kind;
|
||||
|
||||
-- 13. PumpSwap exact amount-source summary.
|
||||
-- Trades must come from transaction/vault deltas or another exact amount source, never from instruction bounds alone.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
json_extract(de.payload_json, '$.amountSource') AS amount_source,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(te.id) AS trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'pump_swap'
|
||||
AND de.event_kind IN (
|
||||
'pump_swap.buy',
|
||||
'pump_swap.sell',
|
||||
'pump_swap.buy_exact_quote_in'
|
||||
)
|
||||
GROUP BY de.event_kind, amount_source
|
||||
ORDER BY de.event_kind, amount_source;
|
||||
|
||||
-- 14. PumpSwap trade/candle parity.
|
||||
-- Expected result: no trade without at least one candle row after candle aggregation.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(DISTINCT te.id) AS trade_count,
|
||||
COUNT(DISTINCT pc.id) AS candle_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
LEFT JOIN k_sol_pair_candles pc
|
||||
ON pc.pair_id = te.pair_id
|
||||
WHERE de.protocol_name = 'pump_swap'
|
||||
GROUP BY de.event_kind
|
||||
ORDER BY de.event_kind;
|
||||
Reference in New Issue
Block a user