0.7.57
This commit is contained in:
@@ -89,3 +89,4 @@
|
||||
0.7.54 - Clôture Pump.fun : decoder maximal local depuis IDL Solscan/upstream, décodage des 40 instructions et 23 events Anchor connus, matérialisation validée des trades `buy/sell/buy_exact_sol_in` et `trade_event` v2/exact sans double-count, non-trades launch/fee/reward/admin selon contexte, validation SQL Pump.fun propre et ouverture de `0.7.55 pump_fees`.
|
||||
0.7.55 - Clôture Pump Fees : decoder local maximal `pump_fees` depuis l'IDL locale, `29` instructions et `20` events Anchor couverts, tests synthétiques des Anchor IDL non observés, matérialisation prudente fee/reward/admin/lifecycle, `get_fees` decoded-only, transactions failed audit-only, aucun trade/candle direct et SQL de validation Pump Fees propre.
|
||||
0.7.56 - Clôture Meteora DBC : decoder local maximal depuis l'IDL `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN`, couverture des 28 instructions et 23 events Anchor, matérialisation validée des swaps `swap/swap2`, lifecycle, admin/config, lockers/migrations et fees/surplus/leftover, ajout du modèle `k_sol_fee_event_amounts` pour les legs de montants fee, helper générique parent fee -> legs scalaires, recovery fee `allowlisted_inner_spl_transfer` strictement allowlistée pour anciens DEX, validation croisée Pump/Raydium, 446 tests passés, clippy OK et SQL de fermeture DBC propre.
|
||||
0.7.57 - Clôture Meteora DLMM : decoder local maximal `meteora_dlmm` sur `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo`, couverture des `76` instructions IDL, `30` events Anchor et `12` accounts, correction du discriminant non-IDL local `75c73e67068e1fcb` en `initialize_preset_parameter_v2`, matérialisation validée des swaps, exact-out, liquidity, bins, positions, lifecycle, fees, rewards, admin/config et limit orders, `swap_event/swap2_evt` routés en lifecycle `swap_log` sans double-count trade/candle, recovery fee/reward strictement allowlistée depuis inner SPL transfers, cleanup coverage duplicates, validation finale `460` tests passés, clippy OK et SQL de fermeture DLMM propre.
|
||||
|
||||
19
Cargo.toml
19
Cargo.toml
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.7.56"
|
||||
version = "0.7.57"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||
@@ -31,24 +31,23 @@ reqwest = { version = "^0.13", default-features = false, features = ["charset",
|
||||
rustls = { version = "^0.23", features = ["aws-lc-rs"] }
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_json = { version = "^1.0", features = [] }
|
||||
solana-account-decoder-client-types = { version = "^4.0", features = ["zstd"] }
|
||||
solana-account-decoder-client-types = { version = ">=4.1.0-rc.1", features = ["zstd"] }
|
||||
solana-address-lookup-table-interface = { version = "^3.1", features = ["serde"] }
|
||||
solana-compute-budget-interface = { version = "^3.0", features = ["borsh", "serde"] }
|
||||
solana-rpc-client-api = { version = ">=4.0.0-rc.0", features = [] }
|
||||
#solana-rpc-client-types = { version = "^4.0", features = [] }
|
||||
solana-rpc-client-api = { version = ">=4.1.0-rc.1", features = [] }
|
||||
solana-sdk = { version = "^4.0", features = ["full"] }
|
||||
solana-sdk-ids = { version = "^3.1", features = [] }
|
||||
solana-system-interface = { version = "^3.2", features = ["alloc", "serde", "std"] }
|
||||
solana-transaction-status-client-types = { version = "^4.0", features = [] }
|
||||
solana-transaction-status-client-types = { version = ">=4.1.0-rc.1", features = [] }
|
||||
spl-associated-token-account-interface = { version = "^2.0", features = ["borsh"] }
|
||||
spl-memo-interface = { version = "^2.1", features = [] }
|
||||
spl-token-interface = { version = "^3.0", features = [] }
|
||||
spl-token-2022-interface = { version = "^3.0", features = [] }
|
||||
spl-token-2022-interface = { version = "^3.1", features = [] }
|
||||
sqlx = { version = "^0.9", features = ["bigdecimal", "chrono", "default", "derive", "json", "runtime-tokio", "sqlite", "tls-rustls", "uuid"] }
|
||||
tauri = { version = "^2.11", features = ["default", "tray-icon"] }
|
||||
tauri-build = { version = "^2.6", features = [] }
|
||||
tauri-plugin-tracing = { version = "^0.3", default-features = false, features = [] }
|
||||
tempfile = { version = "^3", features = [] }
|
||||
tempfile = { version = "^3.27", features = [] }
|
||||
tokio = { version = "^1.52", features = ["full"] }
|
||||
tokio-stream = { version = "^0.1", features = ["full"] }
|
||||
tokio-tungstenite = { version = "^0.29", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots", "stream", "url"] }
|
||||
@@ -56,10 +55,10 @@ tracing = { version = "^0.1", features = [] }
|
||||
tracing-appender = { version = "^0.2", features = [] }
|
||||
tracing-subscriber = { version = "^0.3", features = ["ansi", "env-filter", "chrono", "serde", "json"] }
|
||||
ts-rs = { version = "^12.0", features = ["bigdecimal", "bson", "bytes", "chrono", "indexmap", "ordered-float", "serde_json", "tokio", "url", "uuid"] }
|
||||
yellowstone-grpc-client = { version = "^13.0", features = [] }
|
||||
yellowstone-grpc-proto = { version = "^12.2", features = [] }
|
||||
yellowstone-grpc-client = { version = "^13.1", features = [] }
|
||||
yellowstone-grpc-proto = { version = "^12.4", features = [] }
|
||||
uuid = { version = "^1.23", features = ["v4", "serde"] }
|
||||
zeroize = { version = "^1.8", features = ["derive", "serde", "std"] }
|
||||
zeroize = { version = "^1.9", features = ["derive", "serde", "std"] }
|
||||
|
||||
[profile.dev]
|
||||
incremental = true # Compile your binary in smaller steps.
|
||||
|
||||
97
README.md
97
README.md
@@ -3,6 +3,101 @@
|
||||
# khadhroony-bobobot
|
||||
|
||||
|
||||
## État final validé `0.7.57` — `meteora_dlmm` full decode / full materialization
|
||||
|
||||
La tranche `0.7.57 meteora_dlmm` est clôturée côté decoder local maximal, coverage, tests synthétiques, matérialisation prudente et validation SQL sur base dédiée. Le programme traité est :
|
||||
|
||||
```text
|
||||
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
|
||||
```
|
||||
|
||||
Source IDL locale prioritaire :
|
||||
|
||||
```text
|
||||
idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json
|
||||
```
|
||||
|
||||
Surface couverte : `76` instructions IDL, `30` events Anchor et `12` accounts, avec correction locale du discriminant `75c73e67068e1fcb`, identifié comme `initialize_preset_parameter_v2` par les logs Anchor (`Instruction: InitializePresetParameterV2`) et par hash Anchor. Les entrées observées utiles ne restent pas en decoded-only : elles alimentent `trade`, `liquidity`, `lifecycle`, `fee`, `reward`, `admin` ou `orderbook` selon leur famille.
|
||||
|
||||
Validation locale finale rapportée :
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 460 passed / 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
769 replayed
|
||||
0 decode skipped
|
||||
769 ledger upserts
|
||||
646 unsafe ledger rows
|
||||
106 trades
|
||||
664 liquidity
|
||||
1107 lifecycle
|
||||
0 tokenAccount
|
||||
424 candle upserts
|
||||
instructionObservations = 8062
|
||||
resetDeleted = 9898
|
||||
catalog = 169 tokens / 218 pools / 218 pairs
|
||||
```
|
||||
|
||||
Règles métier verrouillées :
|
||||
|
||||
- les trades/candles DLMM proviennent uniquement des instructions swap fiables : `swap`, `swap2`, `swap_exact_out`, `swap_exact_out2`, `swap_with_price_impact`, `swap_with_price_impact2` ;
|
||||
- `swap_event` et `swap2_evt` sont matérialisés comme `swap_log` lifecycle afin d'éviter tout double comptage trade/candle ;
|
||||
- les positions, bins, pool create, preset parameters, pair status, token badge et operator/config alimentent lifecycle/admin selon contexte ;
|
||||
- les limit orders alimentent `k_sol_orderbook_events` et ne produisent jamais trade/candle ;
|
||||
- les fees DLMM utilisent `k_sol_fee_events` + `k_sol_fee_event_amounts`, avec recovery strictement allowlistée depuis inner SPL transfers ;
|
||||
- les rewards DLMM utilisent une recovery strictement allowlistée, sans inventer de montant pour les initialisations/configurations ;
|
||||
- les transactions failed restent décodées/auditables mais ne matérialisent aucune table métier.
|
||||
|
||||
Synthèse fee/reward finale observée :
|
||||
|
||||
```text
|
||||
claim_fee 64 parents / 64 legs
|
||||
claim_fee2 63 parents / 88 legs
|
||||
claim_fee_event 127 parents / 187 legs
|
||||
claim_fee2_event 78 parents / 118 legs
|
||||
composition_fee_event 51 parents / 63 legs
|
||||
withdraw_protocol_fee 14 parents / 20 legs
|
||||
zap_protocol_fee 13 parents / 13 legs
|
||||
claim_reward 15 parents / 1 scalar amount
|
||||
claim_reward2 19 parents / 10 scalar amounts
|
||||
claim_reward_event 34 parents / 25 scalar amounts
|
||||
claim_reward2_event 19 parents / 10 scalar amounts
|
||||
fund_reward 10 parents / 10 scalar amounts
|
||||
fund_reward_event 10 parents / 10 scalar amounts
|
||||
initialize_reward 9 parents / 0 amount, attendu car init/config
|
||||
initialize_reward_event 9 parents / 0 amount, attendu car init/config
|
||||
```
|
||||
|
||||
Checks de fermeture `0.7.57` :
|
||||
|
||||
- fallback `upstream_git` `meteora_dlmm` pour entrées couvertes localement : vide ;
|
||||
- `instruction_audit` observé : `0` ;
|
||||
- decoded `meteora_dlmm` sans coverage : vide ;
|
||||
- successful non-materialized sans `skip*Reason` ou policy explicite : vide ;
|
||||
- failed transaction avec business materialization : vide ;
|
||||
- multi-target materialization : vide ;
|
||||
- non-swap vers trade/candle : vide ;
|
||||
- parent fee scalaire sans leg : vide ;
|
||||
- fee amount legs orphelins : vide ;
|
||||
- limit/orderbook vers trade/candle : vide ;
|
||||
- duplicate logical coverage rows : vide.
|
||||
|
||||
Écart coverage restant et expliqué : `close_bin_array` affiche `16 observed / 14 materialized`, car `14` transactions sont OK et matérialisées, tandis que `2` transactions failed (`Custom 6015`) restent audit-only.
|
||||
|
||||
Documents de référence :
|
||||
|
||||
```text
|
||||
docs/reports/METEORA_DLMM_EVENT_COVERAGE_REPORT.md
|
||||
docs/VALIDATION_STATUS_0_7_57_FINAL.md
|
||||
validation_sql/SQL_VALIDATION_METEORA_DLMM_0_7_57.sql
|
||||
docs/prompts/PROMPT_0_7_58_DEMO4_PROGRAM_SURFACE_DISCOVERY.md
|
||||
docs/prompts/PROMPT_0_7_59_SQLITE_DB_TRANSACTION_MERGER_BINARY.md
|
||||
docs/prompts/PROMPT_0_7_60_METEORA_DAMM_NEXT_DEX.md
|
||||
```
|
||||
|
||||
Prochaine étape recommandée : `0.7.58 demo4 / program surface discovery`, une fonctionnalité d'affichage et de scoring des contenus non encore pris en compte (`program_id`, discriminators, Anchor logs/events, upstream fallback), sans matérialisation automatique et sans promotion automatique dans les decoders.
|
||||
|
||||
|
||||
|
||||
## État final validé `0.7.56` — `meteora_dbc` + socle `fee_event_amounts`
|
||||
|
||||
@@ -88,7 +183,7 @@ validation_sql/SQL_VALIDATION_METEORA_DBC_0_7_56.sql
|
||||
docs/prompts/PROMPT_0_7_57_METEORA_DLMM_FULL_DECODE_MATERIALIZATION.md
|
||||
```
|
||||
|
||||
Prochaine tranche recommandée : `0.7.57 meteora_dlmm` en mode full decode / full materialization, sur le programme `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo`, avec vérification complète de l'IDL locale `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json`.
|
||||
La tranche suivante `0.7.57 meteora_dlmm` est désormais clôturée. La prochaine étape recommandée est `0.7.58 demo4 / program surface discovery`, puis `0.7.59` pour le binaire de consolidation de bases SQLite.
|
||||
|
||||
## État final validé `0.7.55` — `pump_fees`
|
||||
|
||||
|
||||
459
ROADMAP.md
459
ROADMAP.md
@@ -2,38 +2,45 @@
|
||||
|
||||
# Roadmap — khadhroony-bobobot
|
||||
|
||||
## État courant — clôture `0.7.56 meteora_dbc` et ouverture `0.7.57 meteora_dlmm full decode/materialization`
|
||||
## État courant — clôture `0.7.57 meteora_dlmm` et plan intermédiaire `demo4` / consolidation DB
|
||||
|
||||
### `0.7.56 meteora_dbc` — clos
|
||||
### `0.7.57 meteora_dlmm` — clos
|
||||
|
||||
- Program id : `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN`.
|
||||
- Source prioritaire : `idls/meteora_dbc.dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN.json`.
|
||||
- Surface IDL : `28` instructions, `23` events Anchor, `9` accounts, `59` types.
|
||||
- Build final : `cargo test -p kb_lib` -> `446 passed`; clippy `-D warnings` OK.
|
||||
- Replay final DBC : `480 replayed`, `264 trades`, `1 liquidity`, `122 lifecycle`, `1056 candle upserts`, `instructionObservations=7167`, catalogue `86/60/60`.
|
||||
- Fees DBC : `89` parents `k_sol_fee_events`, `96` legs `k_sol_fee_event_amounts`, aucun parent fee scalaire sans leg, aucun leg orphelin.
|
||||
- Socle transversal ajouté : table `k_sol_fee_event_amounts`, helper générique parent fee + legs, backfill/normalisation safe, recovery `allowlisted_inner_spl_transfer` non globale.
|
||||
- Program id : `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo`.
|
||||
- Source prioritaire : `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json`.
|
||||
- Surface IDL : `76` instructions, `30` events Anchor, `12` accounts.
|
||||
- Build final : `cargo test -p kb_lib` -> `460 passed`; clippy `-D warnings` OK.
|
||||
- Replay final DLMM : `769 replayed`, `106 trades`, `664 liquidity`, `1107 lifecycle`, `424 candle upserts`, `instructionObservations=8062`, catalogue `169/218/218`.
|
||||
- Dernier discriminant résiduel `75c73e67068e1fcb` : identifié comme `initialize_preset_parameter_v2`, matérialisé `4/4` en admin/config.
|
||||
- `instruction_audit` observé : `0`; fallback `upstream_git` DLMM couvert localement : vide.
|
||||
- `close_bin_array` : `16/14` coverage expliqué par `14` transactions OK matérialisées et `2` failed tx `Custom 6015` audit-only.
|
||||
- Checks bloquants : decoded sans coverage, successful non-materialized, failed matérialisé, multi-target, non-swap trade/candle, parent fee sans leg, legs orphelins et coverage duplicates sont propres.
|
||||
|
||||
### Politique fee obligatoire à partir de `0.7.56`
|
||||
### Politique de découverte automatique future
|
||||
|
||||
- Un parent `k_sol_fee_events` avec `fee_token_mint + fee_amount_raw` doit créer automatiquement un leg `k_sol_fee_event_amounts` d'index `0`.
|
||||
- Un fee multi-mint/multi-leg ne doit pas agréger artificiellement le parent ; le parent reste sans montant scalaire, les legs portent les montants fiables.
|
||||
- Les montants issus d'arguments `max`, de bornes ou de `u64::MAX` ne sont pas des fees exécutés.
|
||||
- La recovery par CPI SPL inner transfer n'est pas globale : chaque futur décodeur doit déclarer explicitement sa policy et ses event kinds autorisés.
|
||||
- Les `amount_source` connus à préserver : `parent_fee_event_amount`, `fee_event_amounts`, `inner_spl_transfer`, `lamport_balance_delta`, `allowlisted_inner_spl_transfer`.
|
||||
- Les cas sans transfert exploitable doivent écrire une raison explicite : `fee_instruction_has_no_actual_transfer` ou `fee_instruction_has_only_zero_amount_transfers`.
|
||||
La suite ne doit pas matérialiser automatiquement des contenus inconnus. La future `demo4` doit seulement afficher, scorer et regrouper les surfaces non encore prises en compte pour permettre une programmation manuelle ou semi-automatique contrôlée.
|
||||
|
||||
### Prochaine tranche immédiate
|
||||
À observer sans promotion automatique :
|
||||
|
||||
- `program_id` inconnus ou non routés ;
|
||||
- discriminators inconnus sur program id connu ;
|
||||
- logs Anchor `Instruction: ...` non mappés ;
|
||||
- `Program data` / Anchor events non mappés ;
|
||||
- fallback `upstream_git.instruction_match` ;
|
||||
- layouts accounts/data/inner instructions ;
|
||||
- signatures samples et statut success/failed.
|
||||
|
||||
### Prochaines tranches recommandées
|
||||
|
||||
| Priorité | Tranche | Surface | Objectif |
|
||||
|---:|---|---|---|
|
||||
| 1 | `0.7.57` | `meteora_dlmm` | Full decode + full materialization : `76` instructions IDL, `30` events Anchor, swaps, exact-out, liquidity/bin/position, fees, rewards, admin/config, limit-order events et side effects sans double-count. |
|
||||
| 2 | `0.7.58` | `meteora_damm_v1` | Parité upstream finale : pools, swaps, liquidity, lock, fees/admin. |
|
||||
| 3 | `0.7.59` | `meteora_damm_v2` | Couverture complète : create/custom pools, swaps, liquidity, dynamic config, fees/admin. |
|
||||
| 4 | `0.7.60` | `meteora_vault` | Vault deposit/withdraw/fee/accounting ; pas de candle directe. |
|
||||
| 5 | `0.7.61+` | programmes transversaux | System/SPL/ATA/Compute/Memo/ALT : side effects et contexte, pas de trade direct. |
|
||||
| 1 | `0.7.58` | `demo4_program_surface_discovery` | UI/queries de découverte des contenus non pris en compte : aucun auto-decode métier, aucune auto-materialization, aucune auto-promotion. |
|
||||
| 2 | `0.7.59` | `sqlite_db_transaction_merger` | Nouveau module binaire utilisant `kb_lib` pour fusionner plusieurs bases SQLite de corpus existants dans une base output, sans rescanner/backfill les signatures déjà disponibles. |
|
||||
| 3 | `0.7.60` | `meteora_damm_v1` | Clôture séparée DAMM v1 : pools, swaps, liquidity, lock, fees/admin, coverage et matérialisation complète. |
|
||||
| 4 | `0.7.61` | `meteora_damm_v2` | Clôture séparée DAMM v2 : create/custom pools, swaps, liquidity, dynamic config, fees/admin. |
|
||||
| 5 | `0.7.62` | `meteora_vault` | Vault deposit/withdraw/fee/accounting ; pas de candle directe. |
|
||||
|
||||
La tranche `0.7.57 meteora_dlmm` doit partir d'une base neuve, réutiliser `fee_event_amounts`, ajouter une validation dédiée `validation_sql/SQL_VALIDATION_METEORA_DLMM_0_7_57.sql`, et clôturer uniquement si toutes les entrées IDL locales sont couvertes, décodées ou explicitement non observées avec tests synthétiques.
|
||||
Décision de planification : ne pas fusionner DAMM v1 et DAMM v2 dans une seule tranche. Ils peuvent partager des helpers, des tests et des conventions de matérialisation, mais les `program_id`, IDL, discriminants et corpus doivent rester séparés afin de garder les validations SQL lisibles et de réduire les risques de faux positif.
|
||||
|
||||
## 0.7.47-1FE5 — Décision de planification : ne plus viser “tous les events en une session”
|
||||
|
||||
@@ -62,11 +69,11 @@ Règles de planification :
|
||||
| `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.53+` — une version par `program_id`
|
||||
### Plan actif post-`0.7.57` — phasage par version
|
||||
|
||||
Règle de planification validée après `0.7.52` : **une version cible = un `program_id`**.
|
||||
Règle active après la clôture DLMM : les tranches `0.7.58` et `0.7.59` sont des tranches d’outillage, puis la règle **une version cible = un `program_id`** reprend à partir de `0.7.60`.
|
||||
|
||||
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.
|
||||
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. `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 |
|
||||
|---|---|---|---|---|
|
||||
@@ -74,87 +81,89 @@ Exceptions : les comptes non-programmes (`platform_config`, token authority, com
|
||||
| `0.7.54` | `pump_fun` | `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` | Pump / launch-bonding | **Clos** : decoder maximal IDL/local, trades directs `buy/sell/buy_exact_sol_in`, v2/exact via `trade_event`, non-trades matérialisés selon contexte, validations Pump.fun propres. |
|
||||
| `0.7.55` | `pump_fees` | `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` | Pump / fee | **Clos** : `29` instructions, `20` events Anchor, fee/reward/admin/lifecycle, `get_fees` decoded-only, failed tx audit-only, aucun trade/candle direct. |
|
||||
| `0.7.56` | `meteora_dbc` | `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` | Meteora / DBC | Clos : `28` instructions et `23` events Anchor couverts, swaps `swap/swap2`, lifecycle/admin/fees, `k_sol_fee_event_amounts`, validations SQL propres. |
|
||||
| `0.7.57` | `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | Meteora / DLMM | Full decode + full materialization : `76` instructions IDL, `30` events Anchor, swaps, bins, positions, liquidity, fees/rewards/admin/limit-order, sans double-count. |
|
||||
| `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. |
|
||||
| `0.7.57` | `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | Meteora / DLMM | **Clos** : full decode + full materialization ; `76` instructions IDL, `30` events Anchor, swaps, bins, positions, liquidity, fees/rewards/admin/limit-order, sans double-count. |
|
||||
| `0.7.58` | `demo4_program_surface_discovery` | n/a | Outillage / discovery | Afficher les contenus non pris en compte : program ids, discriminators, Anchor logs/events, upstream fallbacks, layouts et samples ; aucune matérialisation automatique. |
|
||||
| `0.7.59` | `sqlite_db_transaction_merger` | n/a | Outillage / consolidation DB | Ajouter un binaire utilisant `kb_lib` pour fusionner plusieurs `.db` de corpus existants vers une base output sans RPC/backfill. |
|
||||
| `0.7.60` | `meteora_damm_v1` | `Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB` | Meteora / DAMM v1 | Parité upstream finale : pools, swaps, liquidity, lock, fees/admin. |
|
||||
| `0.7.61` | `meteora_damm_v2` | `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` | Meteora / DAMM v2 | Couverture complète : create/custom pools, swaps, liquidity, dynamic config, fees/admin. |
|
||||
| `0.7.62` | `meteora_vault` | `24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi` | Meteora / vault | Vault deposit/withdraw/fee/accounting ; pas de candle directe. |
|
||||
| `0.7.63` | `system_program` | `11111111111111111111111111111111` | Système Solana | Create/assign/transfer account ; side effects de contexte, pas de trade. |
|
||||
| `0.7.64` | `spl_token` | `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` | SPL Token | Transfer, mint, burn, close account, sync native ; base transversale pour deltas. |
|
||||
| `0.7.65` | `spl_token_2022` | `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` | Token-2022 | Transfers/extensions Token-2022, mint/burn/close, comptes et side effects. |
|
||||
| `0.7.66` | `associated_token_account` | `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL` | Système token | Création ATA, rattachement wallet/token/pool. |
|
||||
| `0.7.67` | `compute_budget` | `ComputeBudget111111111111111111111111111111` | Contexte tx | Budget/prioritization fee ; utile scoring/MEV, pas de trade. |
|
||||
| `0.7.68` | `memo` | `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr` | Contexte tx | Mémo transactionnel et attribution éventuelle. |
|
||||
| `0.7.69` | `address_lookup_table` | `AddressLookupTab1e1111111111111111111111111` | Contexte tx | Résolution/diagnostic ALT si nécessaire. |
|
||||
| `0.7.70` | `mpl_token_metadata` | `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s` | Metadata | Enrichissement token/NFT/mint metadata. |
|
||||
| `0.7.71` | `mpl_core` | `CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d` | Metadata / asset | Contexte asset si présent dans corpus. |
|
||||
| `0.7.72` | `bubblegum` | `BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY` | Compressed assets | Audit/contexte assets compressés, pas DEX. |
|
||||
| `0.7.73` | `raydium_routing` | `routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS` | Router | Route/legs Raydium ; éviter le double-count avec DEX effectifs. |
|
||||
| `0.7.74` | `jupiter_swap_v6` | `JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4` | Aggregator | Route attribution, legs, no duplicate trade/candle. |
|
||||
| `0.7.75` | `jupiter_swap_v4` | `JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB` | Legacy aggregator | Audit/route only si corpus encore utile. |
|
||||
| `0.7.76` | `dflow_aggregator_v4` | `DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH` | Aggregator | Route/intent/orderflow ; pas de double matérialisation. |
|
||||
| `0.7.77` | `okx_dex` | `6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma` | Aggregator/router | Route attribution ; trades seulement si source exacte non doublonnée. |
|
||||
| `0.7.78` | `onchain_labs_dex_v2` | `proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u` | Router/DEX candidat | Corpus d’abord ; classifier route vs DEX effectif. |
|
||||
| `0.7.79` | `titan_router` | `T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT` | Router | Audit route-only sauf preuve de trade direct non doublonné. |
|
||||
| `0.7.80` | `sanctum_router` | `stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq` | Router | Route/liquid staking context ; pas de candle DEX directe. |
|
||||
| `0.7.81` | `orca_whirlpools` | `whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc` | DEX avec IDL/source | Swaps, pools, positions, liquidity, fees/rewards. |
|
||||
| `0.7.82` | `stabble_stable_swap` | `swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ` | DEX avec IDL/source | Stable swap ; deltas exacts, liquidity/admin. |
|
||||
| `0.7.83` | `stabble_weighted_swap` | `swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW` | DEX avec IDL/source | Weighted swap, deltas exacts, liquidity/admin. |
|
||||
| `0.7.84` | `stabble_clmm` | `6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6` | DEX avec IDL/source | CLMM Stabble si corpus utile. |
|
||||
| `0.7.85` | `bonkswap` | `BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p` | DEX avec IDL/source | Swap/liquidity/non-trade. |
|
||||
| `0.7.86` | `boop_fun` | `boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4` | Launch/DEX candidat | Launch/swap/migration selon corpus. |
|
||||
| `0.7.87` | `byreal_clmm` | `REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2` | DEX avec IDL/source | CLMM ; corpus puis matérialisation contrôlée. |
|
||||
| `0.7.88` | `fusionamm` | `fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9` | DEX avec IDL/source | AMM ; swaps/liquidity si corpus. |
|
||||
| `0.7.89` | `goosefx_v1` | `GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT` | DEX avec IDL/source | DEX/AMM selon corpus. |
|
||||
| `0.7.90` | `goosefx_v2` | `GFXsSL5sSaDfNFQUYsHekbWBW1TsFdjDYzACh62tEHxn` | DEX avec IDL/source | DEX/AMM selon corpus. |
|
||||
| `0.7.91` | `guac_swap` | `Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1` | DEX avec IDL/source | Swap/liquidity si corpus. |
|
||||
| `0.7.92` | `hylo_exchange` | `HYEXCHtHkBagdStcJCp3xbbb9B7sdMdWXFNj6mdsG4hn` | DEX/source à classifier | Classer DEX/lending/stable selon IDL/corpus. |
|
||||
| `0.7.93` | `printr` | `T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint` | Launch/DEX candidat | Corpus d’abord ; surface launch/swap à confirmer. |
|
||||
| `0.7.94` | `moonit` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Launch/DEX candidat | Launch/migration/swap si prouvé. |
|
||||
| `0.7.95` | `metadao_amm_v0_5` | `AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ` | DEX avec source | AMM futarchy ; corpus et price semantics. |
|
||||
| `0.7.96` | `metadao_bid_wall` | `WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx` | Order/bid-wall | Order/bid-wall context ; pas de candle directe sans fill exact. |
|
||||
| `0.7.97` | `metadao_launchpad` | `moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM` | Launch surface | Launch/ICO surface ; pas DEX effectif par défaut. |
|
||||
| `0.7.98` | `vertigo` | `vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ` | DEX/source | Swap/launch selon corpus. |
|
||||
| `0.7.99` | `virtuals` | `5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki` | Launch/DEX candidat | Launch/AMM à confirmer. |
|
||||
| `0.7.100` | `wavebreak` | `waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF` | DEX/source | Corpus et rôle exact. |
|
||||
| `0.7.101` | `woofi` | `WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb` | DEX/router | Swap/route selon corpus. |
|
||||
| `0.7.102` | `pancake_swap` | `HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq` | DEX/source | DEX Solana à confirmer par corpus. |
|
||||
| `0.7.103` | `gavel` | `srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi` | Source upstream | Corpus d’abord ; rôle exact à classer. |
|
||||
| `0.7.104` | `heaven` | `HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o` | Launch/DEX candidat | Launch/DEX selon corpus. |
|
||||
| `0.7.105` | `lifinity_v2` | `2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c` | DEX legacy/actif | Support selon corpus. |
|
||||
| `0.7.106` | `moonshot` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Source upstream/Solscan | À dédupliquer avec `moonit` si même program id. |
|
||||
| `0.7.107` | `openbook_v2` | `opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb` | Orderbook | Audit/orderbook complet ; trade/candle seulement si fills exacts. |
|
||||
| `0.7.108` | `phoenix_v1` | `PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY` | Orderbook | Audit-only complet avant toute matérialisation fill. |
|
||||
| `0.7.109` | `alphaq` | `ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA` | Solscan/no IDL | Probe par Demo3 + corpus ; décider support ou abandon. |
|
||||
| `0.7.110` | `aquifer` | `AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45` | Solscan/no IDL | Probe uniquement. |
|
||||
| `0.7.111` | `bisonfi` | `BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi` | Solscan/no IDL | Probe uniquement. |
|
||||
| `0.7.112` | `dexlab` | `DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N` | Solscan/no IDL | Vérifier support partiel / corpus. |
|
||||
| `0.7.113` | `fluxbeam` | `FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X` | Solscan/no IDL | Vérifier support partiel / corpus. |
|
||||
| `0.7.114` | `goonfi` | `goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j` | Solscan/no IDL | Probe. |
|
||||
| `0.7.115` | `goonfi_v2` | `goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE` | Solscan/no IDL | Probe ; adresse à revérifier si erreur de taille. |
|
||||
| `0.7.116` | `humidifi` | `9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp` | Solscan/no IDL | Probe. |
|
||||
| `0.7.117` | `obric_v2` | `obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y` | Solscan/no IDL | Probe. |
|
||||
| `0.7.118` | `ondo_global_market` | `XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm` | Solscan IDL | Rôle marché/tokenized assets à confirmer. |
|
||||
| `0.7.119` | `scorch` | `SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn` | Solscan/no IDL | Probe. |
|
||||
| `0.7.120` | `solfi` | `SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe` | Solscan/no IDL | Probe. |
|
||||
| `0.7.121` | `solfi_v2` | `SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF` | Solscan/no IDL | Probe. |
|
||||
| `0.7.122` | `zerofi` | `ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY` | Solscan/no IDL | Probe. |
|
||||
| `0.7.123` | `zora` | `zoRabwLGd5zXaV7Gxacppw8tcceXEiTrSKyNLSaSTUc` | Solscan/no IDL | Probe, pas de promotion sans corpus. |
|
||||
| `0.7.124` | `1dex` | `DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm` | Solscan/no IDL | Probe. |
|
||||
| `0.7.125` | `aldrin_amm` | `AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.126` | `aldrin_amm_v2` | `CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.127` | `crema_finance` | `CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.128` | `cropper_finance` | `CTMAxxk34HjKWxQ3QLZK1HpaLXmBveao3ESePXbiyfzh` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.129` | `cropper_whirlpool` | `H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.130` | `mercurial_stable_swap` | `MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky` | Legacy/no IDL | Historique stable swap ; deltas exacts si support. |
|
||||
| `0.7.131` | `saber_stable_swap` | `SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ` | Legacy/no IDL | Historique stable swap. |
|
||||
| `0.7.132` | `saros_amm` | `SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.133` | `step_finance_swap` | `SSwpMgqNDsyV7mAgN9ady4bDVu5ySjmmXejXvy2vLt1` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.134` | `stepn_dooar_swap` | `Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.135` | `raydium_amm_v2_legacy` | `RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr` | Raydium legacy/no IDL | Historique Raydium ; corpus d’abord. |
|
||||
| `0.7.136` | `raydium_amm_v3_legacy` | `27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv` | Raydium legacy/no IDL | Historique Raydium ; ne pas confondre avec CLMM moderne. |
|
||||
| `0.7.137` | `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.138` | 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.139` | 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`.
|
||||
|
||||
@@ -1422,130 +1431,108 @@ 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. 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`**.
|
||||
### 6.085. Versions `0.7.53` à `0.7.139` — phasage actif post-DLMM
|
||||
|
||||
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.
|
||||
Objectif : maintenir un phasage lisible après la clôture `0.7.57 meteora_dlmm`.
|
||||
|
||||
#### Bloc Pump
|
||||
Décisions actives :
|
||||
|
||||
| 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_fun` | `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` | **Clos** : decoder maximal local, trades directs et `trade_event` canonique, non-trades selon contexte, validations propres. |
|
||||
| `0.7.55` | `pump_fees` | `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` | Couvrir fee accounting/claim/config ; aucun trade/candle direct. |
|
||||
- `0.7.58` est réservé à `demo4_program_surface_discovery` : affichage et revue de surfaces non prises en compte, sans matérialisation automatique.
|
||||
- `0.7.59` est réservé au binaire de consolidation de bases SQLite : fusion de corpus transactionnels déjà présents, sans RPC/backfill.
|
||||
- `0.7.60` reprend le travail DEX avec `meteora_damm_v1`.
|
||||
- `0.7.61` cible `meteora_damm_v2`.
|
||||
- `0.7.62` cible `meteora_vault`.
|
||||
- Après `0.7.62`, le décalage de deux versions est assumé et documenté.
|
||||
|
||||
#### Bloc Meteora
|
||||
|
||||
| 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` | Full decode + full materialization : `76` instructions IDL, `30` events Anchor, swaps, bins, positions, liquidity, fees/rewards/admin/limit-order, sans double-count. |
|
||||
| `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. |
|
||||
|
||||
#### Bloc programmes système / contexte transactionnel
|
||||
|
||||
| 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. |
|
||||
|
||||
#### Bloc routers / aggregators
|
||||
|
||||
| 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. |
|
||||
|
||||
#### Bloc DEX avec IDL/code/source exploitable
|
||||
|
||||
| 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. |
|
||||
|
||||
#### Bloc probes / DEX sans IDL fiable / historiques
|
||||
|
||||
| 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. |
|
||||
|
||||
#### Nettoyage / consolidation
|
||||
|
||||
| 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. |
|
||||
| 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_fun` | `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` | Pump / launch-bonding | **Clos** : decoder maximal IDL/local, trades directs `buy/sell/buy_exact_sol_in`, v2/exact via `trade_event`, non-trades matérialisés selon contexte, validations Pump.fun propres. |
|
||||
| `0.7.55` | `pump_fees` | `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` | Pump / fee | **Clos** : `29` instructions, `20` events Anchor, fee/reward/admin/lifecycle, `get_fees` decoded-only, failed tx audit-only, aucun trade/candle direct. |
|
||||
| `0.7.56` | `meteora_dbc` | `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` | Meteora / DBC | Clos : `28` instructions et `23` events Anchor couverts, swaps `swap/swap2`, lifecycle/admin/fees, `k_sol_fee_event_amounts`, validations SQL propres. |
|
||||
| `0.7.57` | `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | Meteora / DLMM | **Clos** : full decode + full materialization ; `76` instructions IDL, `30` events Anchor, swaps, bins, positions, liquidity, fees/rewards/admin/limit-order, sans double-count. |
|
||||
| `0.7.58` | `demo4_program_surface_discovery` | n/a | Outillage / discovery | Afficher les contenus non pris en compte : program ids, discriminators, Anchor logs/events, upstream fallbacks, layouts et samples ; aucune matérialisation automatique. |
|
||||
| `0.7.59` | `sqlite_db_transaction_merger` | n/a | Outillage / consolidation DB | Ajouter un binaire utilisant `kb_lib` pour fusionner plusieurs `.db` de corpus existants vers une base output sans RPC/backfill. |
|
||||
| `0.7.60` | `meteora_damm_v1` | `Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB` | Meteora / DAMM v1 | Parité upstream finale : pools, swaps, liquidity, lock, fees/admin. |
|
||||
| `0.7.61` | `meteora_damm_v2` | `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` | Meteora / DAMM v2 | Couverture complète : create/custom pools, swaps, liquidity, dynamic config, fees/admin. |
|
||||
| `0.7.62` | `meteora_vault` | `24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi` | Meteora / vault | Vault deposit/withdraw/fee/accounting ; pas de candle directe. |
|
||||
| `0.7.63` | `system_program` | `11111111111111111111111111111111` | Système Solana | Create/assign/transfer account ; side effects de contexte, pas de trade. |
|
||||
| `0.7.64` | `spl_token` | `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` | SPL Token | Transfer, mint, burn, close account, sync native ; base transversale pour deltas. |
|
||||
| `0.7.65` | `spl_token_2022` | `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` | Token-2022 | Transfers/extensions Token-2022, mint/burn/close, comptes et side effects. |
|
||||
| `0.7.66` | `associated_token_account` | `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL` | Système token | Création ATA, rattachement wallet/token/pool. |
|
||||
| `0.7.67` | `compute_budget` | `ComputeBudget111111111111111111111111111111` | Contexte tx | Budget/prioritization fee ; utile scoring/MEV, pas de trade. |
|
||||
| `0.7.68` | `memo` | `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr` | Contexte tx | Mémo transactionnel et attribution éventuelle. |
|
||||
| `0.7.69` | `address_lookup_table` | `AddressLookupTab1e1111111111111111111111111` | Contexte tx | Résolution/diagnostic ALT si nécessaire. |
|
||||
| `0.7.70` | `mpl_token_metadata` | `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s` | Metadata | Enrichissement token/NFT/mint metadata. |
|
||||
| `0.7.71` | `mpl_core` | `CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d` | Metadata / asset | Contexte asset si présent dans corpus. |
|
||||
| `0.7.72` | `bubblegum` | `BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY` | Compressed assets | Audit/contexte assets compressés, pas DEX. |
|
||||
| `0.7.73` | `raydium_routing` | `routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS` | Router | Route/legs Raydium ; éviter le double-count avec DEX effectifs. |
|
||||
| `0.7.74` | `jupiter_swap_v6` | `JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4` | Aggregator | Route attribution, legs, no duplicate trade/candle. |
|
||||
| `0.7.75` | `jupiter_swap_v4` | `JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB` | Legacy aggregator | Audit/route only si corpus encore utile. |
|
||||
| `0.7.76` | `dflow_aggregator_v4` | `DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH` | Aggregator | Route/intent/orderflow ; pas de double matérialisation. |
|
||||
| `0.7.77` | `okx_dex` | `6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma` | Aggregator/router | Route attribution ; trades seulement si source exacte non doublonnée. |
|
||||
| `0.7.78` | `onchain_labs_dex_v2` | `proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u` | Router/DEX candidat | Corpus d’abord ; classifier route vs DEX effectif. |
|
||||
| `0.7.79` | `titan_router` | `T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT` | Router | Audit route-only sauf preuve de trade direct non doublonné. |
|
||||
| `0.7.80` | `sanctum_router` | `stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq` | Router | Route/liquid staking context ; pas de candle DEX directe. |
|
||||
| `0.7.81` | `orca_whirlpools` | `whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc` | DEX avec IDL/source | Swaps, pools, positions, liquidity, fees/rewards. |
|
||||
| `0.7.82` | `stabble_stable_swap` | `swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ` | DEX avec IDL/source | Stable swap ; deltas exacts, liquidity/admin. |
|
||||
| `0.7.83` | `stabble_weighted_swap` | `swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW` | DEX avec IDL/source | Weighted swap, deltas exacts, liquidity/admin. |
|
||||
| `0.7.84` | `stabble_clmm` | `6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6` | DEX avec IDL/source | CLMM Stabble si corpus utile. |
|
||||
| `0.7.85` | `bonkswap` | `BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p` | DEX avec IDL/source | Swap/liquidity/non-trade. |
|
||||
| `0.7.86` | `boop_fun` | `boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4` | Launch/DEX candidat | Launch/swap/migration selon corpus. |
|
||||
| `0.7.87` | `byreal_clmm` | `REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2` | DEX avec IDL/source | CLMM ; corpus puis matérialisation contrôlée. |
|
||||
| `0.7.88` | `fusionamm` | `fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9` | DEX avec IDL/source | AMM ; swaps/liquidity si corpus. |
|
||||
| `0.7.89` | `goosefx_v1` | `GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT` | DEX avec IDL/source | DEX/AMM selon corpus. |
|
||||
| `0.7.90` | `goosefx_v2` | `GFXsSL5sSaDfNFQUYsHekbWBW1TsFdjDYzACh62tEHxn` | DEX avec IDL/source | DEX/AMM selon corpus. |
|
||||
| `0.7.91` | `guac_swap` | `Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1` | DEX avec IDL/source | Swap/liquidity si corpus. |
|
||||
| `0.7.92` | `hylo_exchange` | `HYEXCHtHkBagdStcJCp3xbbb9B7sdMdWXFNj6mdsG4hn` | DEX/source à classifier | Classer DEX/lending/stable selon IDL/corpus. |
|
||||
| `0.7.93` | `printr` | `T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint` | Launch/DEX candidat | Corpus d’abord ; surface launch/swap à confirmer. |
|
||||
| `0.7.94` | `moonit` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Launch/DEX candidat | Launch/migration/swap si prouvé. |
|
||||
| `0.7.95` | `metadao_amm_v0_5` | `AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ` | DEX avec source | AMM futarchy ; corpus et price semantics. |
|
||||
| `0.7.96` | `metadao_bid_wall` | `WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx` | Order/bid-wall | Order/bid-wall context ; pas de candle directe sans fill exact. |
|
||||
| `0.7.97` | `metadao_launchpad` | `moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM` | Launch surface | Launch/ICO surface ; pas DEX effectif par défaut. |
|
||||
| `0.7.98` | `vertigo` | `vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ` | DEX/source | Swap/launch selon corpus. |
|
||||
| `0.7.99` | `virtuals` | `5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki` | Launch/DEX candidat | Launch/AMM à confirmer. |
|
||||
| `0.7.100` | `wavebreak` | `waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF` | DEX/source | Corpus et rôle exact. |
|
||||
| `0.7.101` | `woofi` | `WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb` | DEX/router | Swap/route selon corpus. |
|
||||
| `0.7.102` | `pancake_swap` | `HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq` | DEX/source | DEX Solana à confirmer par corpus. |
|
||||
| `0.7.103` | `gavel` | `srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi` | Source upstream | Corpus d’abord ; rôle exact à classer. |
|
||||
| `0.7.104` | `heaven` | `HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o` | Launch/DEX candidat | Launch/DEX selon corpus. |
|
||||
| `0.7.105` | `lifinity_v2` | `2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c` | DEX legacy/actif | Support selon corpus. |
|
||||
| `0.7.106` | `moonshot` | `MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG` | Source upstream/Solscan | À dédupliquer avec `moonit` si même program id. |
|
||||
| `0.7.107` | `openbook_v2` | `opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb` | Orderbook | Audit/orderbook complet ; trade/candle seulement si fills exacts. |
|
||||
| `0.7.108` | `phoenix_v1` | `PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY` | Orderbook | Audit-only complet avant toute matérialisation fill. |
|
||||
| `0.7.109` | `alphaq` | `ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA` | Solscan/no IDL | Probe par Demo3 + corpus ; décider support ou abandon. |
|
||||
| `0.7.110` | `aquifer` | `AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45` | Solscan/no IDL | Probe uniquement. |
|
||||
| `0.7.111` | `bisonfi` | `BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi` | Solscan/no IDL | Probe uniquement. |
|
||||
| `0.7.112` | `dexlab` | `DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N` | Solscan/no IDL | Vérifier support partiel / corpus. |
|
||||
| `0.7.113` | `fluxbeam` | `FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X` | Solscan/no IDL | Vérifier support partiel / corpus. |
|
||||
| `0.7.114` | `goonfi` | `goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j` | Solscan/no IDL | Probe. |
|
||||
| `0.7.115` | `goonfi_v2` | `goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE` | Solscan/no IDL | Probe ; adresse à revérifier si erreur de taille. |
|
||||
| `0.7.116` | `humidifi` | `9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp` | Solscan/no IDL | Probe. |
|
||||
| `0.7.117` | `obric_v2` | `obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y` | Solscan/no IDL | Probe. |
|
||||
| `0.7.118` | `ondo_global_market` | `XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm` | Solscan IDL | Rôle marché/tokenized assets à confirmer. |
|
||||
| `0.7.119` | `scorch` | `SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn` | Solscan/no IDL | Probe. |
|
||||
| `0.7.120` | `solfi` | `SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe` | Solscan/no IDL | Probe. |
|
||||
| `0.7.121` | `solfi_v2` | `SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF` | Solscan/no IDL | Probe. |
|
||||
| `0.7.122` | `zerofi` | `ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY` | Solscan/no IDL | Probe. |
|
||||
| `0.7.123` | `zora` | `zoRabwLGd5zXaV7Gxacppw8tcceXEiTrSKyNLSaSTUc` | Solscan/no IDL | Probe, pas de promotion sans corpus. |
|
||||
| `0.7.124` | `1dex` | `DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm` | Solscan/no IDL | Probe. |
|
||||
| `0.7.125` | `aldrin_amm` | `AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.126` | `aldrin_amm_v2` | `CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.127` | `crema_finance` | `CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.128` | `cropper_finance` | `CTMAxxk34HjKWxQ3QLZK1HpaLXmBveao3ESePXbiyfzh` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.129` | `cropper_whirlpool` | `H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.130` | `mercurial_stable_swap` | `MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky` | Legacy/no IDL | Historique stable swap ; deltas exacts si support. |
|
||||
| `0.7.131` | `saber_stable_swap` | `SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ` | Legacy/no IDL | Historique stable swap. |
|
||||
| `0.7.132` | `saros_amm` | `SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.133` | `step_finance_swap` | `SSwpMgqNDsyV7mAgN9ady4bDVu5ySjmmXejXvy2vLt1` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.134` | `stepn_dooar_swap` | `Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j` | Legacy/no IDL | Historique/probe. |
|
||||
| `0.7.135` | `raydium_amm_v2_legacy` | `RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr` | Raydium legacy/no IDL | Historique Raydium ; corpus d’abord. |
|
||||
| `0.7.136` | `raydium_amm_v3_legacy` | `27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv` | Raydium legacy/no IDL | Historique Raydium ; ne pas confondre avec CLMM moderne. |
|
||||
| `0.7.137` | `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.138` | 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.139` | base neuve multi-programmes | n/a | Validation consolidée | Replay consolidé, coverage global, zéro faux trade/candle, 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`.
|
||||
|
||||
@@ -1737,8 +1724,8 @@ Préconditions considérées acquises avant cette reprise :
|
||||
Ordre de travail recommandé pour la suite :
|
||||
|
||||
1. `0.7.44` : ledger de décodage/replay et skip sûr — acquis ;
|
||||
2. `0.7.45` : `meteora_dlmm` — clos ;
|
||||
3. `0.7.46` : `meteora_damm_v1` — clos côté corpus local ;
|
||||
2. `0.7.45` : `meteora_dlmm` historique — clos ;
|
||||
3. `0.7.46` : `meteora_damm_v1` historique — 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 ;
|
||||
6. `0.7.48` : `raydium_cpmm` — clos ;
|
||||
@@ -1746,10 +1733,16 @@ Ordre de travail recommandé pour la suite :
|
||||
8. `0.7.50-pre-r2` : `raydium_launchpad` clos + re-vérification CPMM/CLMM ;
|
||||
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_fun` / `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P` ;
|
||||
13. `0.7.55` : `pump_fees` / `pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ` ;
|
||||
14. `0.7.56+` : appliquer le phasage strict “une version = un `program_id`” défini en section `6.085`.
|
||||
11. `0.7.53` : `pump_swap` — clos ;
|
||||
12. `0.7.54` : `pump_fun` — clos ;
|
||||
13. `0.7.55` : `pump_fees` — clos ;
|
||||
14. `0.7.56` : `meteora_dbc` — clos ;
|
||||
15. `0.7.57` : `meteora_dlmm` — clos ;
|
||||
16. `0.7.58` : `demo4_program_surface_discovery` — à faire ;
|
||||
17. `0.7.59` : `sqlite_db_transaction_merger` — à faire ;
|
||||
18. `0.7.60` : `meteora_damm_v1` — prochaine tranche DEX ;
|
||||
19. `0.7.61` : `meteora_damm_v2` — après DAMM v1 ;
|
||||
20. `0.7.62+` : appliquer le phasage actif défini en section `6.085`.
|
||||
|
||||
Garde-fous constants :
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<!-- file: docs/DEX_DECODER_MATRIX.md -->
|
||||
|
||||
# DEX Decoder Matrix — `khadhroony-bobobot` `0.7.56 meteora_dbc closed`
|
||||
# DEX Decoder Matrix — `khadhroony-bobobot` `0.7.57 meteora_dlmm closed`
|
||||
|
||||
|
||||
|
||||
## Note `0.7.57 closed` — Meteora DLMM clôturé et suite discovery
|
||||
|
||||
La tranche `0.7.57` ferme `meteora_dlmm` / `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo`. Elle remplace la couverture partielle historique `0.7.45` par un decoder local maximal aligné sur l'IDL locale, avec correction du discriminant `75c73e67068e1fcb` en `initialize_preset_parameter_v2`. Les résidus observés utiles ne restent plus en decoded-only.
|
||||
|
||||
La prochaine étape n'est pas un nouveau decoder direct, mais `0.7.58 demo4_program_surface_discovery` : affichage et scoring des contenus inconnus/non pris en compte, sans auto-materialization ni auto-promotion.
|
||||
|
||||
## Note `0.7.56 closed` — Meteora DBC clôturé, DLMM ensuite
|
||||
|
||||
La tranche `0.7.56` ferme `meteora_dbc` / `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` depuis l'IDL locale `idls/meteora_dbc.dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN.json`.
|
||||
@@ -81,7 +87,7 @@ Cette matrice complète `kb_lib/src/dex_support_matrix.rs`. Elle documente **ce
|
||||
| 8 | `pump_fun` | `supported / 0.7.54 closed` | Surface launch/bonding/migration Pump.fun couverte localement ; trades directs et `trade_event` canonique validés. | Ne rouvrir que pour bug prouvé ou changement externe. |
|
||||
| 9 | `pump_fees` | `supported / 0.7.55 closed` | Surface fee/config/accounting couverte localement : `29` instructions, `20` events Anchor, fee/reward/admin/lifecycle, tests synthétiques Anchor IDL non observés, failed tx audit-only. | Aucun trade/candle direct ; conserver les deux discriminators Solscan hors IDL comme futures surfaces non observées. |
|
||||
| 10 | `meteora_dbc` | `supported / closed 0.7.56` | Decoder local maximal : `28` instructions, `23` events Anchor, swaps `swap/swap2`, lifecycle/admin/fees, `k_sol_fee_event_amounts`, validation SQL propre. | Ne pas rouvrir sauf bug prouvé ; préserver la policy fee parent+legs et la recovery allowlistée. |
|
||||
| 11 | `meteora_dlmm` | `next / 0.7.57 full decode` | Couverture partielle historique validée en `0.7.45`; IDL locale `76` instructions / `30` events Anchor. | Reprendre depuis base neuve : full decode, full materialization fiable, fees/rewards via `fee_event_amounts`, no double-count avec events Anchor. |
|
||||
| 11 | `meteora_dlmm` | `supported / closed 0.7.57` | Decoder local maximal : `76` instructions IDL, `30` events Anchor, `12` accounts, correction `initialize_preset_parameter_v2`, swaps/exact-out, liquidity, bins, positions, lifecycle, fees/rewards, admin/config et orderbook. | Ne pas rouvrir sauf bug prouvé ; `swap_event/swap2_evt` restent lifecycle `swap_log`, pas trade ; préserver recovery fee/reward allowlistée. |
|
||||
| 12 | `meteora_damm_v1` | `supported / 0.7.58 parity` | Couverture `0.7.46` : swap, create_pool, add/remove liquidity, claim_fee, create_lock_escrow, lock_liquidity. | Vérifier les surfaces upstream non observées ; améliorer rattachement pool/pair pour remove_liquidity non matérialisés ; revalidation stricte. |
|
||||
| 13 | `meteora_damm_v2` | `partial / 0.7.59 planned` | `swap`, `instruction_audit`, registry/discriminants et corpus Demo3 existent. | Couvrir tous les events Carbon/source : create pool, liquidity, fees, dynamic config, admin ; déterminer actionability des swaps ; matérialiser si montants fiables. |
|
||||
| 14 | `phoenix_v1` | `audit-only / 0.7.60 planned` | Decoder local audit-only ; `log_audit`, order place/cancel, withdraw ; parsing strict `0x0f`; events `Reduce`, `Place`, `TimeInForce` observés ; `trade_count=0`. | Terminer tous les events Git : `Fill`, `FillSummary`, `Fee`, `Evict`, `ExpiredOrder`, etc. ; ajouter counts/flags audit ; seulement ensuite étudier trade materialization. |
|
||||
@@ -346,8 +352,14 @@ La tranche a été validée sur base SQLite dédiée : tous les discriminants `0
|
||||
|
||||
Validation finale : `446` tests, clippy OK, `480 replayed`, `264 trades`, `1 liquidity`, `122 lifecycle`, `1056 candles`, `89` parents fee DBC, `96` fee amount legs, invariants SQL propres.
|
||||
|
||||
## 0.7.57 — Meteora DLMM prochain
|
||||
## 0.7.57 — Meteora DLMM clôturé
|
||||
|
||||
| Decoder | Program id | Statut | Source locale | Couverture attendue | Décision métier |
|
||||
| Decoder | Program id | Statut | Source locale | Couverture finale | Décision métier |
|
||||
|---|---|---|---|---|---|
|
||||
| `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | `next / full decode + full materialization` | `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json` | `76` instructions IDL + `30` events Anchor IDL | Swaps/exact-out, liquidity/bin/position, fees/rewards/admin/config, limit order events ; no duplicate trade/candle ; `fee_event_amounts` obligatoire pour fees. |
|
||||
| `meteora_dlmm` | `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo` | `supported / closed 0.7.57` | `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json` | `76` instructions IDL, `30` events Anchor, `12` accounts, `initialize_preset_parameter_v2` ajouté depuis corpus local | Les 6 swaps instructionnels produisent seuls les trades/candles ; Anchor `swap_event/swap2_evt` = lifecycle `swap_log`; liquidity/bin/position/lifecycle/admin/orderbook/fee/reward matérialisés selon cible ; failed tx audit-only. |
|
||||
|
||||
Validation finale : `460` tests, clippy OK, `769 replayed`, `106 trades`, `664 liquidity`, `1107 lifecycle`, `424 candles`, `8062` instruction observations, catalogue `169/218/218`. Checks SQL bloquants propres.
|
||||
|
||||
### 0.7.57 pre.001 — Meteora DLMM
|
||||
|
||||
`meteora_dlmm` passe de tranche `next` à tranche ouverte `pre.001` : l’IDL locale complète est inventoriée, tous les discriminants instruction/event sont classifiés localement, et les familles non prouvées restent decoded-only/audit-safe avec `skip*Reason`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- file: docs/DEX_EVENT_COVERAGE_MATRIX.md -->
|
||||
|
||||
# DEX Event Coverage Matrix — `khadhroony-bobobot` `0.7.54 pump_fun closed`
|
||||
# DEX Event Coverage Matrix — `khadhroony-bobobot` `0.7.57 meteora_dlmm closed`
|
||||
|
||||
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.
|
||||
|
||||
@@ -326,17 +326,28 @@ Programme : `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN`. Source locale priorit
|
||||
|
||||
Validation finale DBC : `89` parents fee, `96` legs fee amount, aucun parent scalaire sans leg, aucun leg orphelin, aucun decoded event local sans coverage, aucun failed tx matérialisé, aucun multi-target, aucun non-swap vers trade/candle.
|
||||
|
||||
## 0.7.57 — Meteora DLMM à reprendre
|
||||
## `0.7.57` — `meteora_dlmm` final coverage
|
||||
|
||||
Programme : `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo`. Source locale : `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json`.
|
||||
Programme : `LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo`. Source locale : `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json`. Surface finale : `76` instructions IDL, `30` events Anchor, `12` accounts, plus correction locale `initialize_preset_parameter_v2` (`75c73e67068e1fcb`) observée dans le corpus.
|
||||
|
||||
| Groupe | Entrées IDL | Famille | Cible DB attendue | Décision à valider |
|
||||
Validation finale : `460` tests, clippy OK, `769` replayed, `106` trades, `664` liquidity, `1107` lifecycle, `424` candle upserts, `8062` instruction observations. Les checks decoded sans coverage, successful non-materialized, failed tx materialized, multi-target, non-swap trade/candle, fee scalar sans leg, orphan fee legs et coverage duplicates sont vides.
|
||||
|
||||
| Famille | Entrées DLMM | Statut `0.7.57` | Cible DB | Justification / règle |
|
||||
|---|---|---|---|---|
|
||||
| swaps | `swap`, `swap2`, `swap_exact_out*`, `swap_with_price_impact*`, `Swap`, `Swap2Evt` | swap | `k_sol_trade_events` + candles | Montants exécutés uniquement ; éviter double-count instruction/event. |
|
||||
| pools / bins | `initialize_*lb_pair*`, `initialize_bin_array*`, `close_bin_array`, `LbPairCreate` | lifecycle | `k_sol_pool_lifecycle_events`, catalog/pair | Catalog si comptes pool/mints/config fiables. |
|
||||
| liquidity / positions | `add_liquidity*`, `remove_liquidity*`, `remove_all_liquidity`, `rebalance_liquidity`, position create/close/update events | liquidity/lifecycle | `k_sol_liquidity_events`, `k_sol_pool_lifecycle_events` | Montants x/y/bin/liquidity fiables ; sinon skip reason. |
|
||||
| fees | `claim_fee*`, `withdraw_protocol_fee`, `zap_protocol_fee`, `ClaimFee*`, `CompositionFee` | fee | `k_sol_fee_events` + `k_sol_fee_event_amounts` | Utiliser le socle fee parent+legs ; policy recovery explicite, non globale. |
|
||||
| rewards | `initialize_reward`, `fund_reward`, `claim_reward*`, `withdraw_ineligible_reward`, reward events | reward | `k_sol_reward_events` | Montant/mint/récompense fiable uniquement. |
|
||||
| admin/config | fee parameters, pair status, activation, operator, token badge, preset parameter | admin_config | `k_sol_pool_admin_events` ou decoded-only | Matérialiser si acteur/compte cible fiable. |
|
||||
| limit/order events | place/cancel/close limit order events | orderbook/audit | `k_sol_orderbook_events` si modèle fiable | Pas de candle directe sans fill exact. |
|
||||
| `swap` | `swap`, `swap2`, `swap_exact_out`, `swap_exact_out2`, `swap_with_price_impact`, `swap_with_price_impact2` | `materialized` | `k_sol_trade_events` + candles | Seules ces instructions produisent trade/candle direct quand montants/mints/pool sont fiables. |
|
||||
| `swap_log` | `swap_event`, `swap2_evt` | `materialized` | `k_sol_pool_lifecycle_events` | Logs Anchor informatifs matérialisés sans double-count trade/candle. |
|
||||
| `pool_create` | `create_pool`, `lb_pair_create_event`, `initialize_*_lb_pair*`, `initialize_permission_lb_pair` | `materialized` si observé, sinon `upstream_git_mapped_unverified` | `k_sol_pool_lifecycle_events` | Pool lifecycle ; pas de trade direct. |
|
||||
| `liquidity_add` | `add_liquidity*`, `add_liquidity_event` | `materialized` | `k_sol_liquidity_events` | Montants/side effects liquidity ; aucun trade/candle. |
|
||||
| `liquidity_remove` | `remove_liquidity*`, `remove_all_liquidity`, `remove_liquidity_event` | `materialized` | `k_sol_liquidity_events` | Retrait liquidity ; failed tx audit-only. |
|
||||
| `liquidity_change` | `rebalance_liquidity`, `rebalancing_event` | `materialized` | `k_sol_liquidity_events` | Changement de liquidité/bin ; pas de trade. |
|
||||
| `position_open` | `initialize_position*`, `position_create_event` | `materialized` | `k_sol_pool_lifecycle_events` | Position/bin lifecycle, pas liquidity artificielle quand l'opération est structurelle. |
|
||||
| `position_close` | `close_position*`, `position_close_event` | `materialized` | `k_sol_pool_lifecycle_events` | Fermeture position lifecycle. |
|
||||
| `position_update` | `increase_position_length*`, `decrease_position_length*`, `update_position_operator*`, position update events | `materialized` si observé | `k_sol_pool_lifecycle_events` | Mise à jour de position ; pas admin générique. |
|
||||
| `bin/oracle lifecycle` | `initialize_bin_array*`, `close_bin_array`, `go_to_a_bin*`, `increase_oracle_length`, `migrate_bin_array` | `materialized` si observé | `k_sol_pool_lifecycle_events` | `close_bin_array` a `16/14` car `2` failed tx `Custom 6015`, comportement attendu. |
|
||||
| `fee` | `claim_fee*`, `claim_fee*_event`, `composition_fee_event`, `withdraw_protocol_fee`, `zap_protocol_fee` | `materialized` | `k_sol_fee_events` + `k_sol_fee_event_amounts` | Recovery inner SPL transfer strictement allowlistée ; legs multi-mint conservés sans agrégation artificielle. |
|
||||
| `reward` | `claim_reward*`, `claim_reward*_event`, `fund_reward*`, `initialize_reward*`, `withdraw_ineligible_reward*` | `materialized` si observé | `k_sol_reward_events` | Claims/funding avec amounts récupérés quand transfert réel ; `initialize_reward*` sans amount est normal. |
|
||||
| `admin/config` | `update_base_fee_parameters`, `fee_parameter_update_event`, `set_pair_status*`, `set_activation_point`, `set_pre_activation*`, preset/token badge/operator/config, `initialize_preset_parameter_v2` | `materialized` si observé | `k_sol_pool_admin_events` | Admin/config non financier ; pas trade/candle. |
|
||||
| `orderbook` | `place_limit_order*`, `cancel_limit_order*`, `close_limit_order*` | `materialized` | `k_sol_orderbook_events` | Limit/orderbook events sans trade/candle. |
|
||||
| `account metadata` | `lb_pair`, `bin_array`, `position_v2`, `oracle`, `operator`, `token_badge`, etc. | `upstream_git_mapped_unverified` / non observé | `k_sol_dex_decoded_events_only` | Accounts IDL listés pour coverage, pas de matérialisation métier directe. |
|
||||
| `instruction_audit` | résidu inconnu | `closed` | `k_sol_pool_admin_events` seulement si observé | Résidu final observé = `0`; `75c73e67068e1fcb` a été promu en `initialize_preset_parameter_v2`. |
|
||||
|
||||
|
||||
73
docs/VALIDATION_STATUS_0_7_57_FINAL.md
Normal file
73
docs/VALIDATION_STATUS_0_7_57_FINAL.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Validation status — 0.7.57 Meteora DLMM final
|
||||
|
||||
## Build
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 460 passed / 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
```
|
||||
|
||||
## Replay
|
||||
|
||||
Recommended replay settings used:
|
||||
|
||||
```text
|
||||
skipDexDecode=no
|
||||
forceDexDecode=yes
|
||||
deferInstructionObservations=yes
|
||||
```
|
||||
|
||||
Final replay summary:
|
||||
|
||||
```text
|
||||
769 replayed
|
||||
0 decode skipped
|
||||
769 ledger upserts
|
||||
646 unsafe ledger rows
|
||||
106 trades
|
||||
664 liquidity
|
||||
1107 lifecycle
|
||||
0 tokenAccount
|
||||
424 candle upserts
|
||||
instructionObservations = 8062
|
||||
resetDeleted = 9898
|
||||
catalog = 169 tokens / 218 pools / 218 pairs
|
||||
```
|
||||
|
||||
## Final SQL gates
|
||||
|
||||
| Gate | Result |
|
||||
|---|---:|
|
||||
| Upstream fallback for local DLMM coverage | empty |
|
||||
| Local `instruction_audit` observed | `0` |
|
||||
| Decoded DLMM without coverage | empty |
|
||||
| Successful non-materialized without explicit skip/policy | empty |
|
||||
| Failed transaction business materialization | empty |
|
||||
| Multi-target materialization | empty |
|
||||
| Non-swap trade/candle safety | empty |
|
||||
| Fee parent scalar without amount leg | empty |
|
||||
| Orphan fee amount legs | empty |
|
||||
| Reward/fee collision | clean separation |
|
||||
| Limit/orderbook trade/candle double-count | empty |
|
||||
| Logical duplicate coverage rows | empty |
|
||||
|
||||
## Final materialization counters
|
||||
|
||||
```text
|
||||
trade events = 106
|
||||
liquidity events = 664
|
||||
lifecycle events = 1107
|
||||
candles = 424
|
||||
```
|
||||
|
||||
## Important decisions
|
||||
|
||||
- `swap_event` and `swap2_evt` are materialized as lifecycle `swap_log`, not as trades.
|
||||
- `initialize_preset_parameter_v2` was added from corpus evidence for discriminator `75c73e67068e1fcb`.
|
||||
- `close_bin_array` has `16` observations but only `14` materializations because `2` transactions failed with `Custom 6015`.
|
||||
- `initialize_reward` and `initialize_reward_event` remain without amounts because they are configuration/init events, not transfers.
|
||||
- No observed useful DLMM event remains decoded-only.
|
||||
|
||||
## Closure decision
|
||||
|
||||
`0.7.57 meteora_dlmm` is considered closed for the validated corpus. Future changes require new corpus evidence.
|
||||
245
docs/prompts/PROMPT_0_7_58_DEMO4_PROGRAM_SURFACE_DISCOVERY.md
Normal file
245
docs/prompts/PROMPT_0_7_58_DEMO4_PROGRAM_SURFACE_DISCOVERY.md
Normal file
@@ -0,0 +1,245 @@
|
||||
<!-- file: docs/prompts/prompt_name_0_7_58_demo4_program_surface_discovery.md -->
|
||||
|
||||
# Prompt — 0.7.58 Demo4 Program Surface Discovery
|
||||
|
||||
## Contexte
|
||||
|
||||
Nous reprenons le workspace Rust/Tauri `khadhroony-bobobot` après la clôture de `0.7.57 meteora_dlmm`.
|
||||
|
||||
État validé :
|
||||
|
||||
```text
|
||||
0.7.57 meteora_dlmm clos
|
||||
cargo test -p kb_lib -> 460 passed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
replay -> 769 replayed, 106 trades, 664 liquidity, 1107 lifecycle, 424 candles
|
||||
instructionObservations = 8062
|
||||
catalogue = 169 tokens / 218 pools / 218 pairs
|
||||
```
|
||||
|
||||
Contraintes projet à respecter :
|
||||
|
||||
- Rust 2024.
|
||||
- Code async-first.
|
||||
- Pas de `?`, `unwrap`, `expect` dans le code applicatif.
|
||||
- Pas de `anyhow`, pas de `thiserror`.
|
||||
- Pas de `mod.rs`.
|
||||
- Pas de `pub mod` ; utiliser `mod` privé + `pub use`.
|
||||
- Imports uniquement pour les traits quand c’est possible.
|
||||
- `#![deny(unreachable_pub)]` et `#![warn(missing_docs)]` doivent rester propres.
|
||||
- Tests offline.
|
||||
- Les nouvelles requêtes DB doivent mettre à jour les re-exports dans `kb_lib/src/db.rs` puis `kb_lib/src/lib.rs`.
|
||||
- Les structs DB doivent aller dans `kb_lib/src/db/entities/*.rs` et `kb_lib/src/db/dtos/*.rs`, pas dans les fichiers de requêtes.
|
||||
|
||||
## Objectif
|
||||
|
||||
Ajouter `Demo4` dans `kb_demo_app` et les fonctions de lecture associées dans `kb_lib` pour afficher les surfaces de programmes non encore prises en compte par le système.
|
||||
|
||||
Cette fonctionnalité est strictement un cockpit de découverte et de revue.
|
||||
|
||||
Elle ne doit pas :
|
||||
|
||||
- matérialiser automatiquement des contenus inconnus ;
|
||||
- promouvoir automatiquement des discriminators inconnus dans les décodeurs officiels ;
|
||||
- marquer automatiquement un `program_id` comme supporté ;
|
||||
- créer automatiquement des lignes `trade`, `candle`, `fee`, `liquidity`, `reward`, `admin` ou `orderbook` depuis un contenu inconnu.
|
||||
|
||||
Elle doit :
|
||||
|
||||
- afficher les surfaces inconnues ou non supportées ;
|
||||
- les regrouper de manière exploitable ;
|
||||
- montrer les preuves et signatures samples ;
|
||||
- aider à produire des prompts/patchs futurs validés manuellement.
|
||||
|
||||
## Comportement attendu côté utilisateur
|
||||
|
||||
Créer une nouvelle page ou fenêtre, selon le pattern existant :
|
||||
|
||||
```text
|
||||
kb_demo_app/src/demo4.html
|
||||
kb_demo_app/src/demo4.ts
|
||||
```
|
||||
|
||||
ou l’équivalent si l’application utilise un autre routage.
|
||||
|
||||
Demo4 doit proposer des vues pour :
|
||||
|
||||
1. discriminators inconnus sur des decoders connus ;
|
||||
2. `program_id` connus contenant des instructions non mappées par le decoder spécialisé ;
|
||||
3. `upstream_git.instruction_match` groupés par `upstreamDecoderCode`, `upstreamEntryName`, `upstreamDiscriminatorHex` ;
|
||||
4. `program_id` observés dans les transactions mais absents de la matrice de support ;
|
||||
5. logs Anchor `Program log: Instruction: ...` non mappés localement ;
|
||||
6. events Anchor `Program data:` non mappés localement ;
|
||||
7. layouts de comptes récurrents sur instructions inconnues ;
|
||||
8. répartition success/failed pour chaque surface candidate.
|
||||
|
||||
Filtres souhaités :
|
||||
|
||||
```text
|
||||
program_id
|
||||
candidate_decoder_code
|
||||
discriminator_hex
|
||||
instruction_name / nom log Anchor
|
||||
upstream decoder
|
||||
upstream entry name
|
||||
success only / failed only / both
|
||||
minimum observation count
|
||||
minimum tx count
|
||||
from slot / to slot
|
||||
signature contains
|
||||
show only unknown
|
||||
show only upstream fallback
|
||||
show only high-confidence candidates
|
||||
```
|
||||
|
||||
Colonnes souhaitées :
|
||||
|
||||
```text
|
||||
candidate_kind
|
||||
program_id
|
||||
candidate_decoder
|
||||
known/unknown status
|
||||
discriminator_hex
|
||||
log_instruction_name
|
||||
anchor_event_discriminator
|
||||
account_count
|
||||
layout_hash
|
||||
observed_count
|
||||
tx_count
|
||||
success_count
|
||||
failed_count
|
||||
first_slot
|
||||
last_slot
|
||||
sample_signature
|
||||
confidence_score
|
||||
confidence_reason
|
||||
status
|
||||
```
|
||||
|
||||
Le panneau de détail doit afficher :
|
||||
|
||||
```text
|
||||
sample signatures
|
||||
accounts_json
|
||||
data_json / data prefix
|
||||
logs de transaction
|
||||
inner instructions
|
||||
parsed_json si disponible
|
||||
decoded_payload_json si disponible
|
||||
entrées upstream registry correspondantes
|
||||
preuve de hash Anchor si un nom d’instruction est disponible
|
||||
```
|
||||
|
||||
## Design `kb_lib`
|
||||
|
||||
Ajouter des requêtes read-only et des DTOs. Fichiers suggérés :
|
||||
|
||||
```text
|
||||
kb_lib/src/program_surface_discovery.rs
|
||||
kb_lib/src/db/dtos/program_surface_candidate_summary.rs
|
||||
kb_lib/src/db/dtos/program_surface_candidate_sample.rs
|
||||
kb_lib/src/db/queries/program_surface_discovery.rs
|
||||
```
|
||||
|
||||
Si un statut persistant est nécessaire, ajouter :
|
||||
|
||||
```text
|
||||
kb_lib/src/db/entities/program_surface_candidate.rs
|
||||
kb_lib/src/db/queries/program_surface_candidates.rs
|
||||
```
|
||||
|
||||
Ne pas placer les DTO/entities dans les fichiers de requêtes.
|
||||
|
||||
Statuts candidats suggérés :
|
||||
|
||||
```text
|
||||
new
|
||||
reviewed
|
||||
accepted
|
||||
rejected
|
||||
promoted
|
||||
ignored
|
||||
```
|
||||
|
||||
Si une table persistante est ajoutée, la migration doit être explicite, idempotente et testée.
|
||||
|
||||
## Scoring de découverte
|
||||
|
||||
Le scoring est indicatif uniquement. Il ne doit jamais déclencher une matérialisation.
|
||||
|
||||
Signaux de confiance possibles :
|
||||
|
||||
| Signal | Effet |
|
||||
|---|---:|
|
||||
| `program_id` connu, discriminator inconnu | +20 |
|
||||
| log Anchor `Instruction: X` trouvé | +30 |
|
||||
| `sha256("global:x")` correspond au discriminator | +50 |
|
||||
| observations success répétées | +10 |
|
||||
| account count/layout stable | +10 |
|
||||
| inner instruction family cohérente avec l’action | +10 |
|
||||
| uniquement des transactions failed | -20 |
|
||||
| nom très générique comme `swap`, `claim`, `initialize` sans autre preuve | -15 |
|
||||
| `program_id` inconnu et observation unique | -25 |
|
||||
|
||||
## Helper Anchor
|
||||
|
||||
Ajouter un helper qui normalise les noms d’instructions Anchor depuis les logs :
|
||||
|
||||
```text
|
||||
Program log: Instruction: InitializePresetParameterV2
|
||||
-> initialize_preset_parameter_v2
|
||||
-> sha256("global:initialize_preset_parameter_v2")[0..8]
|
||||
```
|
||||
|
||||
Ce helper doit seulement produire une preuve/candidate record. Il ne doit pas modifier les mappings de decoder.
|
||||
|
||||
## Export Markdown
|
||||
|
||||
Demo4 doit permettre d’exporter un groupe candidat en Markdown pour une future session d’implémentation.
|
||||
|
||||
L’export doit inclure :
|
||||
|
||||
```text
|
||||
candidate decoder
|
||||
program_id
|
||||
discriminator_hex
|
||||
candidate name
|
||||
confidence score
|
||||
preuves/evidence
|
||||
sample signatures
|
||||
account layout
|
||||
logs
|
||||
inner instruction summary
|
||||
proposed target table éventuelle
|
||||
warning explicite : non implémenté, non matérialisé
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Ajouter des tests offline pour :
|
||||
|
||||
- normalisation des noms Anchor depuis logs ;
|
||||
- calcul de discriminators Anchor pour des noms samples ;
|
||||
- groupement par program/discriminator/layout ;
|
||||
- ordre de score ;
|
||||
- sérialisation/désérialisation des DTOs si utilisés ;
|
||||
- validation des paramètres de commandes UI.
|
||||
|
||||
Aucun test ne doit dépendre de RPC ou du réseau.
|
||||
|
||||
## Validation
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo test -p kb_lib program_surface
|
||||
cargo test -p kb_lib
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
Pour Tauri/frontend, lancer la commande de build/test existante du projet si elle existe.
|
||||
|
||||
## Résultat attendu
|
||||
|
||||
L’utilisateur peut ouvrir Demo4 et voir immédiatement les surfaces unsupported/upstream/unknown présentes dans la base SQLite courante, sans rescanner la blockchain.
|
||||
|
||||
Demo4 est un cockpit de découverte uniquement. Il ne change pas la matérialisation métier.
|
||||
245
docs/prompts/PROMPT_0_7_58_demo4_program_surface_discovery.md
Normal file
245
docs/prompts/PROMPT_0_7_58_demo4_program_surface_discovery.md
Normal file
@@ -0,0 +1,245 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_58_demo4_program_surface_discovery.md -->
|
||||
|
||||
# Prompt — 0.7.58 Demo4 Program Surface Discovery
|
||||
|
||||
## Contexte
|
||||
|
||||
Nous reprenons le workspace Rust/Tauri `khadhroony-bobobot` après la clôture de `0.7.57 meteora_dlmm`.
|
||||
|
||||
État validé :
|
||||
|
||||
```text
|
||||
0.7.57 meteora_dlmm clos
|
||||
cargo test -p kb_lib -> 460 passed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
replay -> 769 replayed, 106 trades, 664 liquidity, 1107 lifecycle, 424 candles
|
||||
instructionObservations = 8062
|
||||
catalogue = 169 tokens / 218 pools / 218 pairs
|
||||
```
|
||||
|
||||
Contraintes projet à respecter :
|
||||
|
||||
- Rust 2024.
|
||||
- Code async-first.
|
||||
- Pas de `?`, `unwrap`, `expect` dans le code applicatif.
|
||||
- Pas de `anyhow`, pas de `thiserror`.
|
||||
- Pas de `mod.rs`.
|
||||
- Pas de `pub mod` ; utiliser `mod` privé + `pub use`.
|
||||
- Imports uniquement pour les traits quand c’est possible.
|
||||
- `#![deny(unreachable_pub)]` et `#![warn(missing_docs)]` doivent rester propres.
|
||||
- Tests offline.
|
||||
- Les nouvelles requêtes DB doivent mettre à jour les re-exports dans `kb_lib/src/db.rs` puis `kb_lib/src/lib.rs`.
|
||||
- Les structs DB doivent aller dans `kb_lib/src/db/entities/*.rs` et `kb_lib/src/db/dtos/*.rs`, pas dans les fichiers de requêtes.
|
||||
|
||||
## Objectif
|
||||
|
||||
Ajouter `Demo4` dans `kb_demo_app` et les fonctions de lecture associées dans `kb_lib` pour afficher les surfaces de programmes non encore prises en compte par le système.
|
||||
|
||||
Cette fonctionnalité est strictement un cockpit de découverte et de revue.
|
||||
|
||||
Elle ne doit pas :
|
||||
|
||||
- matérialiser automatiquement des contenus inconnus ;
|
||||
- promouvoir automatiquement des discriminators inconnus dans les décodeurs officiels ;
|
||||
- marquer automatiquement un `program_id` comme supporté ;
|
||||
- créer automatiquement des lignes `trade`, `candle`, `fee`, `liquidity`, `reward`, `admin` ou `orderbook` depuis un contenu inconnu.
|
||||
|
||||
Elle doit :
|
||||
|
||||
- afficher les surfaces inconnues ou non supportées ;
|
||||
- les regrouper de manière exploitable ;
|
||||
- montrer les preuves et signatures samples ;
|
||||
- aider à produire des prompts/patchs futurs validés manuellement.
|
||||
|
||||
## Comportement attendu côté utilisateur
|
||||
|
||||
Créer une nouvelle page ou fenêtre, selon le pattern existant :
|
||||
|
||||
```text
|
||||
kb_demo_app/src/demo4.html
|
||||
kb_demo_app/src/demo4.ts
|
||||
```
|
||||
|
||||
ou l’équivalent si l’application utilise un autre routage.
|
||||
|
||||
Demo4 doit proposer des vues pour :
|
||||
|
||||
1. discriminators inconnus sur des decoders connus ;
|
||||
2. `program_id` connus contenant des instructions non mappées par le decoder spécialisé ;
|
||||
3. `upstream_git.instruction_match` groupés par `upstreamDecoderCode`, `upstreamEntryName`, `upstreamDiscriminatorHex` ;
|
||||
4. `program_id` observés dans les transactions mais absents de la matrice de support ;
|
||||
5. logs Anchor `Program log: Instruction: ...` non mappés localement ;
|
||||
6. events Anchor `Program data:` non mappés localement ;
|
||||
7. layouts de comptes récurrents sur instructions inconnues ;
|
||||
8. répartition success/failed pour chaque surface candidate.
|
||||
|
||||
Filtres souhaités :
|
||||
|
||||
```text
|
||||
program_id
|
||||
candidate_decoder_code
|
||||
discriminator_hex
|
||||
instruction_name / nom log Anchor
|
||||
upstream decoder
|
||||
upstream entry name
|
||||
success only / failed only / both
|
||||
minimum observation count
|
||||
minimum tx count
|
||||
from slot / to slot
|
||||
signature contains
|
||||
show only unknown
|
||||
show only upstream fallback
|
||||
show only high-confidence candidates
|
||||
```
|
||||
|
||||
Colonnes souhaitées :
|
||||
|
||||
```text
|
||||
candidate_kind
|
||||
program_id
|
||||
candidate_decoder
|
||||
known/unknown status
|
||||
discriminator_hex
|
||||
log_instruction_name
|
||||
anchor_event_discriminator
|
||||
account_count
|
||||
layout_hash
|
||||
observed_count
|
||||
tx_count
|
||||
success_count
|
||||
failed_count
|
||||
first_slot
|
||||
last_slot
|
||||
sample_signature
|
||||
confidence_score
|
||||
confidence_reason
|
||||
status
|
||||
```
|
||||
|
||||
Le panneau de détail doit afficher :
|
||||
|
||||
```text
|
||||
sample signatures
|
||||
accounts_json
|
||||
data_json / data prefix
|
||||
logs de transaction
|
||||
inner instructions
|
||||
parsed_json si disponible
|
||||
decoded_payload_json si disponible
|
||||
entrées upstream registry correspondantes
|
||||
preuve de hash Anchor si un nom d’instruction est disponible
|
||||
```
|
||||
|
||||
## Design `kb_lib`
|
||||
|
||||
Ajouter des requêtes read-only et des DTOs. Fichiers suggérés :
|
||||
|
||||
```text
|
||||
kb_lib/src/program_surface_discovery.rs
|
||||
kb_lib/src/db/dtos/program_surface_candidate_summary.rs
|
||||
kb_lib/src/db/dtos/program_surface_candidate_sample.rs
|
||||
kb_lib/src/db/queries/program_surface_discovery.rs
|
||||
```
|
||||
|
||||
Si un statut persistant est nécessaire, ajouter :
|
||||
|
||||
```text
|
||||
kb_lib/src/db/entities/program_surface_candidate.rs
|
||||
kb_lib/src/db/queries/program_surface_candidates.rs
|
||||
```
|
||||
|
||||
Ne pas placer les DTO/entities dans les fichiers de requêtes.
|
||||
|
||||
Statuts candidats suggérés :
|
||||
|
||||
```text
|
||||
new
|
||||
reviewed
|
||||
accepted
|
||||
rejected
|
||||
promoted
|
||||
ignored
|
||||
```
|
||||
|
||||
Si une table persistante est ajoutée, la migration doit être explicite, idempotente et testée.
|
||||
|
||||
## Scoring de découverte
|
||||
|
||||
Le scoring est indicatif uniquement. Il ne doit jamais déclencher une matérialisation.
|
||||
|
||||
Signaux de confiance possibles :
|
||||
|
||||
| Signal | Effet |
|
||||
|---|---:|
|
||||
| `program_id` connu, discriminator inconnu | +20 |
|
||||
| log Anchor `Instruction: X` trouvé | +30 |
|
||||
| `sha256("global:x")` correspond au discriminator | +50 |
|
||||
| observations success répétées | +10 |
|
||||
| account count/layout stable | +10 |
|
||||
| inner instruction family cohérente avec l’action | +10 |
|
||||
| uniquement des transactions failed | -20 |
|
||||
| nom très générique comme `swap`, `claim`, `initialize` sans autre preuve | -15 |
|
||||
| `program_id` inconnu et observation unique | -25 |
|
||||
|
||||
## Helper Anchor
|
||||
|
||||
Ajouter un helper qui normalise les noms d’instructions Anchor depuis les logs :
|
||||
|
||||
```text
|
||||
Program log: Instruction: InitializePresetParameterV2
|
||||
-> initialize_preset_parameter_v2
|
||||
-> sha256("global:initialize_preset_parameter_v2")[0..8]
|
||||
```
|
||||
|
||||
Ce helper doit seulement produire une preuve/candidate record. Il ne doit pas modifier les mappings de decoder.
|
||||
|
||||
## Export Markdown
|
||||
|
||||
Demo4 doit permettre d’exporter un groupe candidat en Markdown pour une future session d’implémentation.
|
||||
|
||||
L’export doit inclure :
|
||||
|
||||
```text
|
||||
candidate decoder
|
||||
program_id
|
||||
discriminator_hex
|
||||
candidate name
|
||||
confidence score
|
||||
preuves/evidence
|
||||
sample signatures
|
||||
account layout
|
||||
logs
|
||||
inner instruction summary
|
||||
proposed target table éventuelle
|
||||
warning explicite : non implémenté, non matérialisé
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Ajouter des tests offline pour :
|
||||
|
||||
- normalisation des noms Anchor depuis logs ;
|
||||
- calcul de discriminators Anchor pour des noms samples ;
|
||||
- groupement par program/discriminator/layout ;
|
||||
- ordre de score ;
|
||||
- sérialisation/désérialisation des DTOs si utilisés ;
|
||||
- validation des paramètres de commandes UI.
|
||||
|
||||
Aucun test ne doit dépendre de RPC ou du réseau.
|
||||
|
||||
## Validation
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo test -p kb_lib program_surface
|
||||
cargo test -p kb_lib
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
Pour Tauri/frontend, lancer la commande de build/test existante du projet si elle existe.
|
||||
|
||||
## Résultat attendu
|
||||
|
||||
L’utilisateur peut ouvrir Demo4 et voir immédiatement les surfaces unsupported/upstream/unknown présentes dans la base SQLite courante, sans rescanner la blockchain.
|
||||
|
||||
Demo4 est un cockpit de découverte uniquement. Il ne change pas la matérialisation métier.
|
||||
@@ -0,0 +1,249 @@
|
||||
<!-- file: docs/prompts/prompt_name_0_7_59_sqlite_db_transaction_merger_binary.md -->
|
||||
|
||||
# Prompt — 0.7.59 Binaire de fusion de bases SQLite transactionnelles
|
||||
|
||||
## Contexte
|
||||
|
||||
Nous reprenons le workspace Rust `khadhroony-bobobot` après la clôture de `0.7.57 meteora_dlmm` et après/ou en parallèle de `0.7.58 demo4_program_surface_discovery`.
|
||||
|
||||
L’utilisateur possède plusieurs bases SQLite dédiées construites pendant les tranches Raydium, Pump et Meteora. L’objectif est d’éviter de rescanner/backfiller des signatures déjà présentes dans ces bases.
|
||||
|
||||
## Objectif
|
||||
|
||||
Ajouter un module binaire qui utilise `kb_lib` pour fusionner des données de corpus transactionnel depuis plusieurs fichiers SQLite `.db` vers une base SQLite de sortie unique.
|
||||
|
||||
Le merger doit copier suffisamment de données brutes transaction/instruction pour permettre un replay local dans la base consolidée, sans refaire les appels RPC.
|
||||
|
||||
Ce binaire est un outil de consolidation de corpus. Ce n’est pas un scanner blockchain.
|
||||
|
||||
## Forme recommandée
|
||||
|
||||
Créer un nouveau package workspace :
|
||||
|
||||
```text
|
||||
kb_tools/
|
||||
Cargo.toml
|
||||
src/bin/kb_db_merge.rs
|
||||
```
|
||||
|
||||
Le binaire doit dépendre de `kb_lib` et réutiliser autant que possible les fonctions de schéma/setup/query existantes.
|
||||
|
||||
Alternative acceptable si le workspace préfère ce pattern :
|
||||
|
||||
```text
|
||||
kb_lib/src/bin/kb_db_merge.rs
|
||||
```
|
||||
|
||||
Préférer `kb_tools` si cela évite de mélanger du code CLI-only dans `kb_lib`.
|
||||
|
||||
## Interface CLI
|
||||
|
||||
Commande suggérée :
|
||||
|
||||
```bash
|
||||
cargo run -p kb_tools --bin kb_db_merge -- \
|
||||
--output ./merged_corpus.db \
|
||||
--input ./raydium.db \
|
||||
--input ./pump.db \
|
||||
--input ./meteora.db \
|
||||
--mode raw-corpus \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
Options requises ou utiles :
|
||||
|
||||
```text
|
||||
--output <path>
|
||||
--input <path> répétable
|
||||
--mode <mode>
|
||||
--dry-run optionnel
|
||||
--replace-output optionnel ; sinon refuser si output existe
|
||||
--source-label optionnel ou inféré depuis le nom de fichier
|
||||
--limit optionnel pour tests
|
||||
```
|
||||
|
||||
Modes initiaux :
|
||||
|
||||
```text
|
||||
raw-corpus
|
||||
full-copy-safe
|
||||
signatures-only
|
||||
```
|
||||
|
||||
## Mode `raw-corpus`
|
||||
|
||||
Mode par défaut recommandé.
|
||||
|
||||
Copier les données brutes canonique nécessaires au replay local sans RPC :
|
||||
|
||||
```text
|
||||
k_sol_chain_transactions
|
||||
k_sol_chain_instructions
|
||||
```
|
||||
|
||||
Si le schéma contient d’autres tables brutes/contextuelles strictement nécessaires, les inspecter avant de les ajouter. Ne copier que les tables sûres, sans duplication sémantique.
|
||||
|
||||
La base output doit ensuite pouvoir exécuter le replay/décodage local depuis les transactions persistées.
|
||||
|
||||
## Mode `full-copy-safe`
|
||||
|
||||
Mode optionnel pour plus tard.
|
||||
|
||||
Copier aussi des lignes décodées/matérialisées seulement si les foreign keys, versions de decoder et versions de schéma sont cohérentes.
|
||||
|
||||
Ne pas l’implémenter comme mode par défaut. Il est plus dangereux car les lignes matérialisées dépendent de la version du code.
|
||||
|
||||
## Mode `signatures-only`
|
||||
|
||||
Copier uniquement les signatures/slots dans une table de staging afin qu’un outil futur décide quoi importer/rejouer.
|
||||
|
||||
## Politique de déduplication
|
||||
|
||||
Identité primaire :
|
||||
|
||||
```text
|
||||
signature
|
||||
```
|
||||
|
||||
Règles :
|
||||
|
||||
- Une même signature dans plusieurs inputs doit produire une seule transaction dans l’output.
|
||||
- Si `meta_json`, `transaction_json`, `slot` ou `err_json` diffèrent pour une même signature, enregistrer un conflit ; ne pas écraser silencieusement.
|
||||
- Préférer la ligne brute la plus complète uniquement si le conflit est explicable et journalisé.
|
||||
- Conserver la provenance dans des tables d’audit de merge.
|
||||
|
||||
Tables suggérées :
|
||||
|
||||
```text
|
||||
k_sol_db_merge_sources
|
||||
k_sol_db_merge_transactions
|
||||
k_sol_db_merge_conflicts
|
||||
```
|
||||
|
||||
Champs source suggérés :
|
||||
|
||||
```text
|
||||
source_id
|
||||
source_path
|
||||
source_label
|
||||
source_schema_version
|
||||
source_created_at
|
||||
input_transaction_count
|
||||
copied_transaction_count
|
||||
skipped_duplicate_count
|
||||
conflict_count
|
||||
```
|
||||
|
||||
Pour chaque signature copiée :
|
||||
|
||||
```text
|
||||
signature
|
||||
slot
|
||||
source_id
|
||||
source_transaction_id
|
||||
copied_at
|
||||
copy_status
|
||||
conflict_status
|
||||
```
|
||||
|
||||
## Règles de sécurité
|
||||
|
||||
- Ne pas appeler RPC.
|
||||
- Ne pas backfiller.
|
||||
- Ne pas décoder DEX pendant le merge.
|
||||
- Ne pas matérialiser trades/candles pendant le merge.
|
||||
- Ne pas supposer une compatibilité de schéma sans inspection.
|
||||
- Ne pas utiliser `ATTACH` avec des chemins non validés/échappés.
|
||||
- Pas de `?`, `unwrap`, `expect` dans le code applicatif.
|
||||
- Les erreurs doivent être explicites, typées projet, et lisibles.
|
||||
- Le mode dry-run doit indiquer exactement ce qui serait copié, ignoré ou marqué conflictuel.
|
||||
|
||||
## Compatibilité de schéma
|
||||
|
||||
Le binaire doit inspecter `sqlite_master` et `PRAGMA table_info(...)` dans chaque DB input.
|
||||
|
||||
Tables requises pour `raw-corpus` :
|
||||
|
||||
```text
|
||||
k_sol_chain_transactions
|
||||
k_sol_chain_instructions
|
||||
```
|
||||
|
||||
Vérifier les colonnes requises par nom. Si une colonne optionnelle manque, l’indiquer clairement et continuer seulement si la copie reste suffisante pour un replay local fiable.
|
||||
|
||||
Si le schéma est incompatible, échouer proprement avec un résumé court.
|
||||
|
||||
## Stratégie de copie
|
||||
|
||||
Algorithme recommandé :
|
||||
|
||||
1. Ouvrir/créer la base output et initialiser le schéma courant via `kb_lib`.
|
||||
2. Pour chaque input DB :
|
||||
- inspecter le schéma ;
|
||||
- enregistrer la source ;
|
||||
- itérer les transactions par slot/signature ;
|
||||
- si la signature est absente de l’output, insérer la transaction et ses instructions enfants ;
|
||||
- si la signature existe, comparer les champs canoniques et ignorer ou enregistrer un conflit ;
|
||||
- préserver le mapping `source_transaction_id -> output_transaction_id` pour les instructions.
|
||||
3. Commit par batches.
|
||||
4. Imprimer un résumé final.
|
||||
|
||||
La taille de batch doit être configurable ou conservatrice.
|
||||
|
||||
## SQL de validation
|
||||
|
||||
Ajouter :
|
||||
|
||||
```text
|
||||
validation_sql/SQL_VALIDATION_DB_MERGE_0_7_59.sql
|
||||
```
|
||||
|
||||
Checks minimaux :
|
||||
|
||||
```sql
|
||||
-- duplicate signatures in output should be empty
|
||||
SELECT signature, COUNT(*)
|
||||
FROM k_sol_chain_transactions
|
||||
GROUP BY signature
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- orphan instructions should be empty
|
||||
SELECT ins.id
|
||||
FROM k_sol_chain_instructions ins
|
||||
LEFT JOIN k_sol_chain_transactions tx ON tx.id = ins.transaction_id
|
||||
WHERE tx.id IS NULL;
|
||||
|
||||
-- conflicts summary
|
||||
SELECT *
|
||||
FROM k_sol_db_merge_conflicts
|
||||
ORDER BY id DESC
|
||||
LIMIT 100;
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Ajouter des tests offline avec bases SQLite temporaires :
|
||||
|
||||
1. merge d’une DB vers un output vide ;
|
||||
2. merge de deux DBs avec signatures disjointes ;
|
||||
3. merge de deux DBs avec signature identique et contenu identique ;
|
||||
4. signature dupliquée avec conflit slot/meta et ligne conflict enregistrée ;
|
||||
5. instructions recopiées avec le nouveau `transaction_id` output ;
|
||||
6. dry-run sans écriture des lignes output ;
|
||||
7. table requise manquante -> erreur propre.
|
||||
|
||||
## Documentation
|
||||
|
||||
Mettre à jour :
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
validation_sql/SQL_VALIDATION_DB_MERGE_0_7_59.sql
|
||||
docs/reports/SQLITE_DB_TRANSACTION_MERGER_0_7_59.md
|
||||
```
|
||||
|
||||
## Résultat attendu
|
||||
|
||||
L’utilisateur peut consolider ses anciennes bases Raydium/Pump/Meteora dans une base output et relancer un replay local depuis les lignes brutes existantes, sans refaire les backfills RPC de signatures.
|
||||
@@ -0,0 +1,249 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_59_sqlite_db_transaction_merger_binary.md -->
|
||||
|
||||
# Prompt — 0.7.59 Binaire de fusion de bases SQLite transactionnelles
|
||||
|
||||
## Contexte
|
||||
|
||||
Nous reprenons le workspace Rust `khadhroony-bobobot` après la clôture de `0.7.57 meteora_dlmm` et après/ou en parallèle de `0.7.58 demo4_program_surface_discovery`.
|
||||
|
||||
L’utilisateur possède plusieurs bases SQLite dédiées construites pendant les tranches Raydium, Pump et Meteora. L’objectif est d’éviter de rescanner/backfiller des signatures déjà présentes dans ces bases.
|
||||
|
||||
## Objectif
|
||||
|
||||
Ajouter un module binaire qui utilise `kb_lib` pour fusionner des données de corpus transactionnel depuis plusieurs fichiers SQLite `.db` vers une base SQLite de sortie unique.
|
||||
|
||||
Le merger doit copier suffisamment de données brutes transaction/instruction pour permettre un replay local dans la base consolidée, sans refaire les appels RPC.
|
||||
|
||||
Ce binaire est un outil de consolidation de corpus. Ce n’est pas un scanner blockchain.
|
||||
|
||||
## Forme recommandée
|
||||
|
||||
Créer un nouveau package workspace :
|
||||
|
||||
```text
|
||||
kb_tools/
|
||||
Cargo.toml
|
||||
src/bin/kb_db_merge.rs
|
||||
```
|
||||
|
||||
Le binaire doit dépendre de `kb_lib` et réutiliser autant que possible les fonctions de schéma/setup/query existantes.
|
||||
|
||||
Alternative acceptable si le workspace préfère ce pattern :
|
||||
|
||||
```text
|
||||
kb_lib/src/bin/kb_db_merge.rs
|
||||
```
|
||||
|
||||
Préférer `kb_tools` si cela évite de mélanger du code CLI-only dans `kb_lib`.
|
||||
|
||||
## Interface CLI
|
||||
|
||||
Commande suggérée :
|
||||
|
||||
```bash
|
||||
cargo run -p kb_tools --bin kb_db_merge -- \
|
||||
--output ./merged_corpus.db \
|
||||
--input ./raydium.db \
|
||||
--input ./pump.db \
|
||||
--input ./meteora.db \
|
||||
--mode raw-corpus \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
Options requises ou utiles :
|
||||
|
||||
```text
|
||||
--output <path>
|
||||
--input <path> répétable
|
||||
--mode <mode>
|
||||
--dry-run optionnel
|
||||
--replace-output optionnel ; sinon refuser si output existe
|
||||
--source-label optionnel ou inféré depuis le nom de fichier
|
||||
--limit optionnel pour tests
|
||||
```
|
||||
|
||||
Modes initiaux :
|
||||
|
||||
```text
|
||||
raw-corpus
|
||||
full-copy-safe
|
||||
signatures-only
|
||||
```
|
||||
|
||||
## Mode `raw-corpus`
|
||||
|
||||
Mode par défaut recommandé.
|
||||
|
||||
Copier les données brutes canonique nécessaires au replay local sans RPC :
|
||||
|
||||
```text
|
||||
k_sol_chain_transactions
|
||||
k_sol_chain_instructions
|
||||
```
|
||||
|
||||
Si le schéma contient d’autres tables brutes/contextuelles strictement nécessaires, les inspecter avant de les ajouter. Ne copier que les tables sûres, sans duplication sémantique.
|
||||
|
||||
La base output doit ensuite pouvoir exécuter le replay/décodage local depuis les transactions persistées.
|
||||
|
||||
## Mode `full-copy-safe`
|
||||
|
||||
Mode optionnel pour plus tard.
|
||||
|
||||
Copier aussi des lignes décodées/matérialisées seulement si les foreign keys, versions de decoder et versions de schéma sont cohérentes.
|
||||
|
||||
Ne pas l’implémenter comme mode par défaut. Il est plus dangereux car les lignes matérialisées dépendent de la version du code.
|
||||
|
||||
## Mode `signatures-only`
|
||||
|
||||
Copier uniquement les signatures/slots dans une table de staging afin qu’un outil futur décide quoi importer/rejouer.
|
||||
|
||||
## Politique de déduplication
|
||||
|
||||
Identité primaire :
|
||||
|
||||
```text
|
||||
signature
|
||||
```
|
||||
|
||||
Règles :
|
||||
|
||||
- Une même signature dans plusieurs inputs doit produire une seule transaction dans l’output.
|
||||
- Si `meta_json`, `transaction_json`, `slot` ou `err_json` diffèrent pour une même signature, enregistrer un conflit ; ne pas écraser silencieusement.
|
||||
- Préférer la ligne brute la plus complète uniquement si le conflit est explicable et journalisé.
|
||||
- Conserver la provenance dans des tables d’audit de merge.
|
||||
|
||||
Tables suggérées :
|
||||
|
||||
```text
|
||||
k_sol_db_merge_sources
|
||||
k_sol_db_merge_transactions
|
||||
k_sol_db_merge_conflicts
|
||||
```
|
||||
|
||||
Champs source suggérés :
|
||||
|
||||
```text
|
||||
source_id
|
||||
source_path
|
||||
source_label
|
||||
source_schema_version
|
||||
source_created_at
|
||||
input_transaction_count
|
||||
copied_transaction_count
|
||||
skipped_duplicate_count
|
||||
conflict_count
|
||||
```
|
||||
|
||||
Pour chaque signature copiée :
|
||||
|
||||
```text
|
||||
signature
|
||||
slot
|
||||
source_id
|
||||
source_transaction_id
|
||||
copied_at
|
||||
copy_status
|
||||
conflict_status
|
||||
```
|
||||
|
||||
## Règles de sécurité
|
||||
|
||||
- Ne pas appeler RPC.
|
||||
- Ne pas backfiller.
|
||||
- Ne pas décoder DEX pendant le merge.
|
||||
- Ne pas matérialiser trades/candles pendant le merge.
|
||||
- Ne pas supposer une compatibilité de schéma sans inspection.
|
||||
- Ne pas utiliser `ATTACH` avec des chemins non validés/échappés.
|
||||
- Pas de `?`, `unwrap`, `expect` dans le code applicatif.
|
||||
- Les erreurs doivent être explicites, typées projet, et lisibles.
|
||||
- Le mode dry-run doit indiquer exactement ce qui serait copié, ignoré ou marqué conflictuel.
|
||||
|
||||
## Compatibilité de schéma
|
||||
|
||||
Le binaire doit inspecter `sqlite_master` et `PRAGMA table_info(...)` dans chaque DB input.
|
||||
|
||||
Tables requises pour `raw-corpus` :
|
||||
|
||||
```text
|
||||
k_sol_chain_transactions
|
||||
k_sol_chain_instructions
|
||||
```
|
||||
|
||||
Vérifier les colonnes requises par nom. Si une colonne optionnelle manque, l’indiquer clairement et continuer seulement si la copie reste suffisante pour un replay local fiable.
|
||||
|
||||
Si le schéma est incompatible, échouer proprement avec un résumé court.
|
||||
|
||||
## Stratégie de copie
|
||||
|
||||
Algorithme recommandé :
|
||||
|
||||
1. Ouvrir/créer la base output et initialiser le schéma courant via `kb_lib`.
|
||||
2. Pour chaque input DB :
|
||||
- inspecter le schéma ;
|
||||
- enregistrer la source ;
|
||||
- itérer les transactions par slot/signature ;
|
||||
- si la signature est absente de l’output, insérer la transaction et ses instructions enfants ;
|
||||
- si la signature existe, comparer les champs canoniques et ignorer ou enregistrer un conflit ;
|
||||
- préserver le mapping `source_transaction_id -> output_transaction_id` pour les instructions.
|
||||
3. Commit par batches.
|
||||
4. Imprimer un résumé final.
|
||||
|
||||
La taille de batch doit être configurable ou conservatrice.
|
||||
|
||||
## SQL de validation
|
||||
|
||||
Ajouter :
|
||||
|
||||
```text
|
||||
validation_sql/SQL_VALIDATION_DB_MERGE_0_7_59.sql
|
||||
```
|
||||
|
||||
Checks minimaux :
|
||||
|
||||
```sql
|
||||
-- duplicate signatures in output should be empty
|
||||
SELECT signature, COUNT(*)
|
||||
FROM k_sol_chain_transactions
|
||||
GROUP BY signature
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- orphan instructions should be empty
|
||||
SELECT ins.id
|
||||
FROM k_sol_chain_instructions ins
|
||||
LEFT JOIN k_sol_chain_transactions tx ON tx.id = ins.transaction_id
|
||||
WHERE tx.id IS NULL;
|
||||
|
||||
-- conflicts summary
|
||||
SELECT *
|
||||
FROM k_sol_db_merge_conflicts
|
||||
ORDER BY id DESC
|
||||
LIMIT 100;
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Ajouter des tests offline avec bases SQLite temporaires :
|
||||
|
||||
1. merge d’une DB vers un output vide ;
|
||||
2. merge de deux DBs avec signatures disjointes ;
|
||||
3. merge de deux DBs avec signature identique et contenu identique ;
|
||||
4. signature dupliquée avec conflit slot/meta et ligne conflict enregistrée ;
|
||||
5. instructions recopiées avec le nouveau `transaction_id` output ;
|
||||
6. dry-run sans écriture des lignes output ;
|
||||
7. table requise manquante -> erreur propre.
|
||||
|
||||
## Documentation
|
||||
|
||||
Mettre à jour :
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
validation_sql/SQL_VALIDATION_DB_MERGE_0_7_59.sql
|
||||
docs/reports/SQLITE_DB_TRANSACTION_MERGER_0_7_59.md
|
||||
```
|
||||
|
||||
## Résultat attendu
|
||||
|
||||
L’utilisateur peut consolider ses anciennes bases Raydium/Pump/Meteora dans une base output et relancer un replay local depuis les lignes brutes existantes, sans refaire les backfills RPC de signatures.
|
||||
198
docs/prompts/PROMPT_0_7_60_METEORA_DAMM_NEXT_DEX.md
Normal file
198
docs/prompts/PROMPT_0_7_60_METEORA_DAMM_NEXT_DEX.md
Normal file
@@ -0,0 +1,198 @@
|
||||
<!-- file: docs/prompts/prompt_name_0_7_60_meteora_damm_next_dex.md -->
|
||||
|
||||
# Prompt — 0.7.60 Meteora DAMM v1 puis DAMM v2
|
||||
|
||||
## Décision
|
||||
|
||||
Ne pas fusionner Meteora DAMM v1 et Meteora DAMM v2 dans une seule tranche d’implémentation.
|
||||
|
||||
Utiliser des versions séparées :
|
||||
|
||||
```text
|
||||
0.7.60 -> meteora_damm_v1
|
||||
0.7.61 -> meteora_damm_v2
|
||||
```
|
||||
|
||||
Raison :
|
||||
|
||||
- `program_id` différents ;
|
||||
- surfaces IDL/discriminators différentes ;
|
||||
- corpus historiques et besoins de validation différents ;
|
||||
- clôture SQL plus lisible ;
|
||||
- risque réduit de faux positifs cross-version ;
|
||||
- rollback plus simple si une version contient une hypothèse incorrecte.
|
||||
|
||||
Partage autorisé :
|
||||
|
||||
- helpers communs privés ;
|
||||
- patterns communs de récupération fee/reward amounts ;
|
||||
- conventions communes de coverage/tests ;
|
||||
- structure commune de rapport ;
|
||||
- template SQL commun.
|
||||
|
||||
Ne pas partager la classification de decoder d’une manière qui masque les discriminators version-spécifiques ou les layouts propres à chaque programme.
|
||||
|
||||
## Contexte
|
||||
|
||||
`0.7.57 meteora_dlmm` est clos. Les tranches intermédiaires planifiées sont :
|
||||
|
||||
```text
|
||||
0.7.58 -> demo4_program_surface_discovery
|
||||
0.7.59 -> sqlite_db_transaction_merger
|
||||
```
|
||||
|
||||
La prochaine tranche DEX doit reprendre la famille Meteora après DLMM/DBC, en commençant par DAMM v1.
|
||||
|
||||
Surfaces Meteora connues :
|
||||
|
||||
```text
|
||||
meteora_dbc -> clos 0.7.56
|
||||
meteora_dlmm -> clos 0.7.57
|
||||
meteora_damm_v1 -> 0.7.60
|
||||
meteora_damm_v2 -> 0.7.61
|
||||
meteora_vault -> plus tard, surface séparée
|
||||
```
|
||||
|
||||
## Cible 0.7.60 — meteora_damm_v1
|
||||
|
||||
Program id depuis la roadmap :
|
||||
|
||||
```text
|
||||
Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB
|
||||
```
|
||||
|
||||
Objectif principal :
|
||||
|
||||
```text
|
||||
Full decode + full materialization pour toutes les instructions/events DAMM v1 disponibles depuis les IDL locales et les sources upstream.
|
||||
```
|
||||
|
||||
Familles attendues :
|
||||
|
||||
```text
|
||||
swap
|
||||
pool_create
|
||||
add_liquidity
|
||||
remove_liquidity
|
||||
lock/unlock liquidity si présent
|
||||
fee/admin/config
|
||||
lifecycle/migration si présent
|
||||
```
|
||||
|
||||
Règles :
|
||||
|
||||
- Pas de decoded-only pour une entrée utile observée si elle peut être matérialisée sûrement.
|
||||
- Ne pas créer de trade/candle depuis des non-swaps.
|
||||
- Ne pas matérialiser les transactions failed.
|
||||
- Ne pas agréger artificiellement les fees multi-mint.
|
||||
- Utiliser `k_sol_fee_event_amounts` pour les legs fee fiables.
|
||||
- Utiliser la récupération inner SPL transfer seulement avec allowlist explicite et tests.
|
||||
- Conserver toutes les entrées IDL/upstream non observées dans la coverage avec `0/0` et proof status clair.
|
||||
|
||||
## Sources à vérifier
|
||||
|
||||
Inspecter d’abord le répertoire local :
|
||||
|
||||
```text
|
||||
idls/
|
||||
```
|
||||
|
||||
Puis comparer avec :
|
||||
|
||||
```text
|
||||
Carbon decoders
|
||||
Pinax/substreams-solana-idls
|
||||
0xfnzero sol-parser-sdk / solana-streamer
|
||||
ancien code local et rapports historiques du projet
|
||||
samples Solscan / backfills Demo3
|
||||
```
|
||||
|
||||
Ne pas considérer les anciens résultats `0.7.36` ou `0.7.46` comme clôture finale. Revalider depuis le schéma courant et les règles actuelles de matérialisation.
|
||||
|
||||
## Plan de travail
|
||||
|
||||
1. Créer ou rafraîchir les entrées coverage `meteora_damm_v1`.
|
||||
2. Vérifier le `program_id` et la surface IDL locale.
|
||||
3. Étendre l’enum/local classifier des discriminators.
|
||||
4. Ajouter le naming dans `instruction_observation_index`.
|
||||
5. Décoder toutes les instructions et tous les events Anchor disponibles.
|
||||
6. Matérialiser swaps, liquidity, lifecycle, fee, reward/admin/orderbook si applicable.
|
||||
7. Ajouter des tests synthétiques pour chaque instruction/event IDL, y compris non observé.
|
||||
8. Ajouter le SQL de validation.
|
||||
9. Rejouer sur base fraîche avec :
|
||||
|
||||
```text
|
||||
skipDexDecode=no
|
||||
forceDexDecode=yes
|
||||
deferInstructionObservations=yes
|
||||
```
|
||||
|
||||
10. Clore seulement si les gates SQL sont propres.
|
||||
|
||||
## Gates SQL obligatoires
|
||||
|
||||
Reprendre le pattern DLMM :
|
||||
|
||||
```text
|
||||
fallback upstream pour entrées localement couvertes -> vide
|
||||
instruction_name null/blank -> vide
|
||||
decoded sans coverage -> vide
|
||||
successful non-materialized without skip/policy -> vide
|
||||
failed tx materialization -> vide
|
||||
multi-target materialization -> vide
|
||||
non-swap trade/candle -> vide
|
||||
fee scalar parent without leg -> vide
|
||||
orphan fee legs -> vide
|
||||
coverage logical duplicates -> vide
|
||||
watchlist sans backlog meteora_damm_v1
|
||||
```
|
||||
|
||||
## Cible 0.7.61 — meteora_damm_v2
|
||||
|
||||
Program id depuis la roadmap :
|
||||
|
||||
```text
|
||||
cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
|
||||
```
|
||||
|
||||
N’ouvrir cette tranche qu’après clôture DAMM v1.
|
||||
|
||||
La tranche v2 peut réutiliser le template et des helpers privés, mais doit conserver ses propres éléments :
|
||||
|
||||
```text
|
||||
decoder code
|
||||
coverage entries
|
||||
instruction enum
|
||||
event mapping
|
||||
synthetic tests
|
||||
SQL validation
|
||||
rapport
|
||||
```
|
||||
|
||||
## Livrables attendus pour 0.7.60
|
||||
|
||||
Fichiers probables :
|
||||
|
||||
```text
|
||||
kb_lib/src/dex/meteora_damm_v1.rs
|
||||
kb_lib/src/dex_event_coverage.rs
|
||||
kb_lib/src/dex_event_classification.rs
|
||||
kb_lib/src/instruction_observation_index.rs
|
||||
kb_lib/src/non_trade_event_materialization.rs
|
||||
validation_sql/SQL_VALIDATION_METEORA_DAMM_V1_0_7_60.sql
|
||||
docs/reports/METEORA_DAMM_V1_EVENT_COVERAGE_REPORT.md
|
||||
```
|
||||
|
||||
Mettre à jour les re-exports si des modules ou requêtes sont ajoutés :
|
||||
|
||||
```text
|
||||
kb_lib/src/dex.rs
|
||||
kb_lib/src/lib.rs
|
||||
kb_lib/src/db.rs
|
||||
```
|
||||
|
||||
## Note finale
|
||||
|
||||
Si la découverte corpus montre que DAMM v1 et v2 partagent une logique basse-niveau précise, créer des helpers privés communs.
|
||||
|
||||
Ne pas fusionner les deux protocoles dans un seul decoder, une seule coverage ou un seul rapport de clôture.
|
||||
198
docs/prompts/PROMPT_0_7_60_meteora_damm_next_dex.md
Normal file
198
docs/prompts/PROMPT_0_7_60_meteora_damm_next_dex.md
Normal file
@@ -0,0 +1,198 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_60_meteora_damm_next_dex.md -->
|
||||
|
||||
# Prompt — 0.7.60 Meteora DAMM v1 puis DAMM v2
|
||||
|
||||
## Décision
|
||||
|
||||
Ne pas fusionner Meteora DAMM v1 et Meteora DAMM v2 dans une seule tranche d’implémentation.
|
||||
|
||||
Utiliser des versions séparées :
|
||||
|
||||
```text
|
||||
0.7.60 -> meteora_damm_v1
|
||||
0.7.61 -> meteora_damm_v2
|
||||
```
|
||||
|
||||
Raison :
|
||||
|
||||
- `program_id` différents ;
|
||||
- surfaces IDL/discriminators différentes ;
|
||||
- corpus historiques et besoins de validation différents ;
|
||||
- clôture SQL plus lisible ;
|
||||
- risque réduit de faux positifs cross-version ;
|
||||
- rollback plus simple si une version contient une hypothèse incorrecte.
|
||||
|
||||
Partage autorisé :
|
||||
|
||||
- helpers communs privés ;
|
||||
- patterns communs de récupération fee/reward amounts ;
|
||||
- conventions communes de coverage/tests ;
|
||||
- structure commune de rapport ;
|
||||
- template SQL commun.
|
||||
|
||||
Ne pas partager la classification de decoder d’une manière qui masque les discriminators version-spécifiques ou les layouts propres à chaque programme.
|
||||
|
||||
## Contexte
|
||||
|
||||
`0.7.57 meteora_dlmm` est clos. Les tranches intermédiaires planifiées sont :
|
||||
|
||||
```text
|
||||
0.7.58 -> demo4_program_surface_discovery
|
||||
0.7.59 -> sqlite_db_transaction_merger
|
||||
```
|
||||
|
||||
La prochaine tranche DEX doit reprendre la famille Meteora après DLMM/DBC, en commençant par DAMM v1.
|
||||
|
||||
Surfaces Meteora connues :
|
||||
|
||||
```text
|
||||
meteora_dbc -> clos 0.7.56
|
||||
meteora_dlmm -> clos 0.7.57
|
||||
meteora_damm_v1 -> 0.7.60
|
||||
meteora_damm_v2 -> 0.7.61
|
||||
meteora_vault -> plus tard, surface séparée
|
||||
```
|
||||
|
||||
## Cible 0.7.60 — meteora_damm_v1
|
||||
|
||||
Program id depuis la roadmap :
|
||||
|
||||
```text
|
||||
Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB
|
||||
```
|
||||
|
||||
Objectif principal :
|
||||
|
||||
```text
|
||||
Full decode + full materialization pour toutes les instructions/events DAMM v1 disponibles depuis les IDL locales et les sources upstream.
|
||||
```
|
||||
|
||||
Familles attendues :
|
||||
|
||||
```text
|
||||
swap
|
||||
pool_create
|
||||
add_liquidity
|
||||
remove_liquidity
|
||||
lock/unlock liquidity si présent
|
||||
fee/admin/config
|
||||
lifecycle/migration si présent
|
||||
```
|
||||
|
||||
Règles :
|
||||
|
||||
- Pas de decoded-only pour une entrée utile observée si elle peut être matérialisée sûrement.
|
||||
- Ne pas créer de trade/candle depuis des non-swaps.
|
||||
- Ne pas matérialiser les transactions failed.
|
||||
- Ne pas agréger artificiellement les fees multi-mint.
|
||||
- Utiliser `k_sol_fee_event_amounts` pour les legs fee fiables.
|
||||
- Utiliser la récupération inner SPL transfer seulement avec allowlist explicite et tests.
|
||||
- Conserver toutes les entrées IDL/upstream non observées dans la coverage avec `0/0` et proof status clair.
|
||||
|
||||
## Sources à vérifier
|
||||
|
||||
Inspecter d’abord le répertoire local :
|
||||
|
||||
```text
|
||||
idls/
|
||||
```
|
||||
|
||||
Puis comparer avec :
|
||||
|
||||
```text
|
||||
Carbon decoders
|
||||
Pinax/substreams-solana-idls
|
||||
0xfnzero sol-parser-sdk / solana-streamer
|
||||
ancien code local et rapports historiques du projet
|
||||
samples Solscan / backfills Demo3
|
||||
```
|
||||
|
||||
Ne pas considérer les anciens résultats `0.7.36` ou `0.7.46` comme clôture finale. Revalider depuis le schéma courant et les règles actuelles de matérialisation.
|
||||
|
||||
## Plan de travail
|
||||
|
||||
1. Créer ou rafraîchir les entrées coverage `meteora_damm_v1`.
|
||||
2. Vérifier le `program_id` et la surface IDL locale.
|
||||
3. Étendre l’enum/local classifier des discriminators.
|
||||
4. Ajouter le naming dans `instruction_observation_index`.
|
||||
5. Décoder toutes les instructions et tous les events Anchor disponibles.
|
||||
6. Matérialiser swaps, liquidity, lifecycle, fee, reward/admin/orderbook si applicable.
|
||||
7. Ajouter des tests synthétiques pour chaque instruction/event IDL, y compris non observé.
|
||||
8. Ajouter le SQL de validation.
|
||||
9. Rejouer sur base fraîche avec :
|
||||
|
||||
```text
|
||||
skipDexDecode=no
|
||||
forceDexDecode=yes
|
||||
deferInstructionObservations=yes
|
||||
```
|
||||
|
||||
10. Clore seulement si les gates SQL sont propres.
|
||||
|
||||
## Gates SQL obligatoires
|
||||
|
||||
Reprendre le pattern DLMM :
|
||||
|
||||
```text
|
||||
fallback upstream pour entrées localement couvertes -> vide
|
||||
instruction_name null/blank -> vide
|
||||
decoded sans coverage -> vide
|
||||
successful non-materialized without skip/policy -> vide
|
||||
failed tx materialization -> vide
|
||||
multi-target materialization -> vide
|
||||
non-swap trade/candle -> vide
|
||||
fee scalar parent without leg -> vide
|
||||
orphan fee legs -> vide
|
||||
coverage logical duplicates -> vide
|
||||
watchlist sans backlog meteora_damm_v1
|
||||
```
|
||||
|
||||
## Cible 0.7.61 — meteora_damm_v2
|
||||
|
||||
Program id depuis la roadmap :
|
||||
|
||||
```text
|
||||
cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
|
||||
```
|
||||
|
||||
N’ouvrir cette tranche qu’après clôture DAMM v1.
|
||||
|
||||
La tranche v2 peut réutiliser le template et des helpers privés, mais doit conserver ses propres éléments :
|
||||
|
||||
```text
|
||||
decoder code
|
||||
coverage entries
|
||||
instruction enum
|
||||
event mapping
|
||||
synthetic tests
|
||||
SQL validation
|
||||
rapport
|
||||
```
|
||||
|
||||
## Livrables attendus pour 0.7.60
|
||||
|
||||
Fichiers probables :
|
||||
|
||||
```text
|
||||
kb_lib/src/dex/meteora_damm_v1.rs
|
||||
kb_lib/src/dex_event_coverage.rs
|
||||
kb_lib/src/dex_event_classification.rs
|
||||
kb_lib/src/instruction_observation_index.rs
|
||||
kb_lib/src/non_trade_event_materialization.rs
|
||||
validation_sql/SQL_VALIDATION_METEORA_DAMM_V1_0_7_60.sql
|
||||
docs/reports/METEORA_DAMM_V1_EVENT_COVERAGE_REPORT.md
|
||||
```
|
||||
|
||||
Mettre à jour les re-exports si des modules ou requêtes sont ajoutés :
|
||||
|
||||
```text
|
||||
kb_lib/src/dex.rs
|
||||
kb_lib/src/lib.rs
|
||||
kb_lib/src/db.rs
|
||||
```
|
||||
|
||||
## Note finale
|
||||
|
||||
Si la découverte corpus montre que DAMM v1 et v2 partagent une logique basse-niveau précise, créer des helpers privés communs.
|
||||
|
||||
Ne pas fusionner les deux protocoles dans un seul decoder, une seule coverage ou un seul rapport de clôture.
|
||||
182
docs/reports/METEORA_DLMM_EVENT_COVERAGE_REPORT.md
Normal file
182
docs/reports/METEORA_DLMM_EVENT_COVERAGE_REPORT.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Meteora DLMM event coverage report — 0.7.57 final
|
||||
|
||||
## Scope
|
||||
|
||||
Version `0.7.57` closes `meteora_dlmm` from the local IDL and the dedicated local corpus.
|
||||
|
||||
Target program:
|
||||
|
||||
```text
|
||||
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
|
||||
```
|
||||
|
||||
Local IDL:
|
||||
|
||||
```text
|
||||
idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json
|
||||
```
|
||||
|
||||
Final inventoried surface:
|
||||
|
||||
```text
|
||||
76 IDL instructions
|
||||
30 Anchor events
|
||||
12 accounts
|
||||
```
|
||||
|
||||
The local corpus additionally identified discriminator `75c73e67068e1fcb` as `initialize_preset_parameter_v2`. This discriminator was not present in the local IDL under that spelling, but the transaction logs contain `Instruction: InitializePresetParameterV2`, the account layout is stable, and the instruction creates a 36-byte DLMM-owned preset parameter account through the system program.
|
||||
|
||||
## Final validation summary
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 460 passed / 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
769 replayed
|
||||
0 decode skipped
|
||||
769 ledger upserts
|
||||
646 unsafe ledger rows
|
||||
106 trades
|
||||
664 liquidity
|
||||
1107 lifecycle
|
||||
0 tokenAccount
|
||||
424 candle upserts
|
||||
instructionObservations = 8062
|
||||
resetDeleted = 9898
|
||||
catalog = 169 tokens / 218 pools / 218 pairs
|
||||
```
|
||||
|
||||
## Closure checks
|
||||
|
||||
All blocking checks are clean:
|
||||
|
||||
```text
|
||||
upstream_git fallback for locally covered meteora_dlmm entries -> empty
|
||||
local instruction_audit observed -> 0
|
||||
DLMM decoded events without coverage -> empty
|
||||
successful non-materialized DLMM without explicit skip/policy -> empty
|
||||
failed transaction business materialization -> empty
|
||||
multi-target materialization -> empty
|
||||
non-swap trade/candle safety -> empty
|
||||
fee parent scalar without fee amount leg -> empty
|
||||
orphan fee amount legs -> empty
|
||||
limit/orderbook trade/candle double-count -> empty
|
||||
logical duplicate coverage rows -> empty
|
||||
```
|
||||
|
||||
The only coverage difference left is explained and non-blocking:
|
||||
|
||||
```text
|
||||
close_bin_array observed 16 / materialized 14
|
||||
14 successful transactions -> lifecycle materialized
|
||||
2 failed transactions Custom 6015 -> decoded/audit only, no business materialization
|
||||
```
|
||||
|
||||
## Materialization policy
|
||||
|
||||
### Trades and candles
|
||||
|
||||
Only instruction-level DLMM swaps can produce trades/candles:
|
||||
|
||||
```text
|
||||
meteora_dlmm.swap
|
||||
meteora_dlmm.swap2
|
||||
meteora_dlmm.swap_exact_out
|
||||
meteora_dlmm.swap_exact_out2
|
||||
meteora_dlmm.swap_with_price_impact
|
||||
meteora_dlmm.swap_with_price_impact2
|
||||
```
|
||||
|
||||
Anchor `swap_event` and `swap2_evt` are materialized as lifecycle `swap_log` rows and never as trades/candles. This prevents double-counting when an instruction swap and an Anchor log describe the same user-visible swap.
|
||||
|
||||
### Liquidity and lifecycle
|
||||
|
||||
The following families are materialized when transactions are successful and context is reliable:
|
||||
|
||||
```text
|
||||
add_liquidity*
|
||||
remove_liquidity*
|
||||
remove_all_liquidity
|
||||
rebalance_liquidity
|
||||
initialize_bin_array*
|
||||
close_bin_array
|
||||
go_to_a_bin*
|
||||
initialize_position*
|
||||
close_position*
|
||||
increase_position_length*
|
||||
decrease_position_length*
|
||||
update_position_operator*
|
||||
lb_pair_create_event
|
||||
position_create_event
|
||||
position_close_event
|
||||
```
|
||||
|
||||
Position and bin lifecycle events are routed to `k_sol_pool_lifecycle_events` when the operation is structural rather than a direct liquidity amount delta.
|
||||
|
||||
### Fees
|
||||
|
||||
Fee parents are written to `k_sol_fee_events`. Amount legs are written to `k_sol_fee_event_amounts`.
|
||||
|
||||
Final observed amount-leg summary:
|
||||
|
||||
```text
|
||||
claim_fee 64 parents / 64 legs
|
||||
claim_fee2 63 parents / 88 legs
|
||||
claim_fee_event 127 parents / 187 legs
|
||||
claim_fee2_event 78 parents / 118 legs
|
||||
composition_fee_event 51 parents / 63 legs
|
||||
withdraw_protocol_fee 14 parents / 20 legs
|
||||
zap_protocol_fee 13 parents / 13 legs
|
||||
```
|
||||
|
||||
The inner SPL transfer recovery is explicitly allowlisted for DLMM fee event kinds. It is not inherited globally by future decoders.
|
||||
|
||||
### Rewards
|
||||
|
||||
Reward parents are written to `k_sol_reward_events`. Amounts are recovered only when a reliable inner SPL transfer or decoded amount is present.
|
||||
|
||||
Final observed scalar amount summary:
|
||||
|
||||
```text
|
||||
claim_reward 15 parents / 1 scalar amount
|
||||
claim_reward2 19 parents / 10 scalar amounts
|
||||
claim_reward_event 34 parents / 25 scalar amounts
|
||||
claim_reward2_event 19 parents / 10 scalar amounts
|
||||
fund_reward 10 parents / 10 scalar amounts
|
||||
fund_reward_event 10 parents / 10 scalar amounts
|
||||
initialize_reward 9 parents / 0 amount
|
||||
initialize_reward_event 9 parents / 0 amount
|
||||
```
|
||||
|
||||
`initialize_reward` and `initialize_reward_event` remain without amount because they are configuration/initialization events, not executed reward transfers. No amount is fabricated from limits, bounds or configuration fields.
|
||||
|
||||
### Admin/config and orderbook
|
||||
|
||||
Admin/config events materialize to `k_sol_pool_admin_events`. Limit-order operations materialize to `k_sol_orderbook_events` and never to trade/candle tables.
|
||||
|
||||
Important promoted local corpus entry:
|
||||
|
||||
```text
|
||||
75c73e67068e1fcb -> meteora_dlmm.initialize_preset_parameter_v2 -> k_sol_pool_admin_events
|
||||
```
|
||||
|
||||
## Remaining non-observed surfaces
|
||||
|
||||
Non-observed IDL/account rows remain in coverage with `observed_count = 0` and `materialized_count = 0`. They are not blockers.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
update_reward_duration
|
||||
update_reward_funder
|
||||
withdraw_ineligible_reward
|
||||
migrate_position
|
||||
account metadata rows
|
||||
for_idl_type_generation_do_not_call
|
||||
anchor_self_cpi_log registry row
|
||||
```
|
||||
|
||||
## Decision
|
||||
|
||||
`0.7.57 meteora_dlmm` is closed. Do not add further DLMM Rust patches unless a new corpus proves a successful transaction that is decoded but not materialized and lacks an explicit skip/policy reason.
|
||||
|
||||
Next recommended work is not another DLMM patch: implement `0.7.58 demo4_program_surface_discovery` to display unknown or unsupported program surfaces without automatic materialization or automatic decoder promotion.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "kb-demo-app",
|
||||
"private": true,
|
||||
"version": "0.7.56",
|
||||
"version": "0.7.57",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "kb-demo-app",
|
||||
"version": "0.7.56",
|
||||
"version": "0.7.57",
|
||||
"identifier": "com.sasedev.kb-demo-app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1126,7 +1126,7 @@ impl DexDecodeService {
|
||||
event.instruction_id,
|
||||
"meteora_dlmm",
|
||||
event.program_id.clone(),
|
||||
"meteora_dlmm.swap",
|
||||
event.event_kind.as_str(),
|
||||
event.pool_account.clone(),
|
||||
None,
|
||||
event.token_a_mint.clone(),
|
||||
@@ -4273,6 +4273,18 @@ fn candidate_meteora_audit_pool_account(
|
||||
return accounts.get(index).cloned();
|
||||
}
|
||||
|
||||
fn is_meteora_dlmm_instruction_swap_event_kind(event_kind: &str) -> bool {
|
||||
return matches!(
|
||||
event_kind,
|
||||
"meteora_dlmm.swap"
|
||||
| "meteora_dlmm.swap2"
|
||||
| "meteora_dlmm.swap_exact_out"
|
||||
| "meteora_dlmm.swap_exact_out2"
|
||||
| "meteora_dlmm.swap_with_price_impact"
|
||||
| "meteora_dlmm.swap_with_price_impact2"
|
||||
);
|
||||
}
|
||||
|
||||
fn is_meteora_dlmm_anchor_swap_log_replaced_by_decoded_swap(
|
||||
protocol_name: &str,
|
||||
instruction: &crate::ChainInstructionDto,
|
||||
@@ -4294,7 +4306,7 @@ fn is_meteora_dlmm_anchor_swap_log_replaced_by_decoded_swap(
|
||||
}
|
||||
for decoded_event in decoded_events {
|
||||
if decoded_event.protocol_name == "meteora_dlmm"
|
||||
&& decoded_event.event_kind == "meteora_dlmm.swap"
|
||||
&& is_meteora_dlmm_instruction_swap_event_kind(decoded_event.event_kind.as_str())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -170,7 +170,12 @@ pub(crate) fn dex_detection_route(
|
||||
("meteora_dlmm", "meteora_dlmm.create_pool") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::MeteoraDlmmPool);
|
||||
},
|
||||
("meteora_dlmm", "meteora_dlmm.swap") => {
|
||||
("meteora_dlmm", "meteora_dlmm.swap")
|
||||
| ("meteora_dlmm", "meteora_dlmm.swap2")
|
||||
| ("meteora_dlmm", "meteora_dlmm.swap_exact_out")
|
||||
| ("meteora_dlmm", "meteora_dlmm.swap_exact_out2")
|
||||
| ("meteora_dlmm", "meteora_dlmm.swap_with_price_impact")
|
||||
| ("meteora_dlmm", "meteora_dlmm.swap_with_price_impact2") => {
|
||||
return Some(crate::dex_detection_route::DexDetectionRoute::MeteoraDlmmPool);
|
||||
},
|
||||
("meteora_damm_v1", "meteora_damm_v1.create_pool") => {
|
||||
|
||||
@@ -323,6 +323,9 @@ pub fn is_dex_informational_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true when the event kind represents a swap-like event.
|
||||
pub fn is_dex_trade_event_kind(event_kind: &str) -> bool {
|
||||
if is_meteora_dlmm_anchor_swap_log_event_kind(event_kind) {
|
||||
return false;
|
||||
}
|
||||
if event_kind == "raydium_launchpad.trade_event" {
|
||||
return true;
|
||||
}
|
||||
@@ -376,8 +379,126 @@ pub fn is_dex_candle_candidate_event_kind(event_kind: &str) -> bool {
|
||||
return is_dex_trade_event_kind(event_kind);
|
||||
}
|
||||
|
||||
fn is_meteora_dlmm_anchor_swap_log_event_kind(event_kind: &str) -> bool {
|
||||
return matches!(event_kind, "meteora_dlmm.swap_event" | "meteora_dlmm.swap2_evt");
|
||||
}
|
||||
|
||||
fn is_meteora_dlmm_position_lifecycle_event_kind(event_kind: &str) -> bool {
|
||||
if !event_kind.starts_with("meteora_dlmm.") {
|
||||
return false;
|
||||
}
|
||||
return matches!(
|
||||
event_kind,
|
||||
"meteora_dlmm.initialize_position"
|
||||
| "meteora_dlmm.initialize_position2"
|
||||
| "meteora_dlmm.initialize_position_by_operator"
|
||||
| "meteora_dlmm.initialize_position_pda"
|
||||
| "meteora_dlmm.position_create_event"
|
||||
| "meteora_dlmm.close_position"
|
||||
| "meteora_dlmm.close_position2"
|
||||
| "meteora_dlmm.close_position_if_empty"
|
||||
| "meteora_dlmm.position_close_event"
|
||||
| "meteora_dlmm.decrease_position_length"
|
||||
| "meteora_dlmm.decrease_position_length_event"
|
||||
| "meteora_dlmm.increase_position_length"
|
||||
| "meteora_dlmm.increase_position_length2"
|
||||
| "meteora_dlmm.increase_position_length_event"
|
||||
| "meteora_dlmm.update_position_operator"
|
||||
| "meteora_dlmm.update_position_operator_event"
|
||||
| "meteora_dlmm.update_position_lock_release_point_event"
|
||||
| "meteora_dlmm.set_position_permissionless_operation_bits_evt"
|
||||
);
|
||||
}
|
||||
|
||||
fn is_meteora_dlmm_pool_lifecycle_event_kind(event_kind: &str) -> bool {
|
||||
if !event_kind.starts_with("meteora_dlmm.") {
|
||||
return false;
|
||||
}
|
||||
if is_meteora_dlmm_position_lifecycle_event_kind(event_kind) {
|
||||
return true;
|
||||
}
|
||||
return matches!(
|
||||
event_kind,
|
||||
"meteora_dlmm.create_pool"
|
||||
| "meteora_dlmm.swap_event"
|
||||
| "meteora_dlmm.swap2_evt"
|
||||
| "meteora_dlmm.lb_pair_create_event"
|
||||
| "meteora_dlmm.initialize_lb_pair"
|
||||
| "meteora_dlmm.initialize_lb_pair2"
|
||||
| "meteora_dlmm.initialize_permission_lb_pair"
|
||||
| "meteora_dlmm.initialize_customizable_permissionless_lb_pair"
|
||||
| "meteora_dlmm.initialize_customizable_permissionless_lb_pair2"
|
||||
| "meteora_dlmm.initialize_bin_array"
|
||||
| "meteora_dlmm.initialize_bin_array_bitmap_extension"
|
||||
| "meteora_dlmm.close_bin_array"
|
||||
| "meteora_dlmm.go_to_a_bin"
|
||||
| "meteora_dlmm.go_to_a_bin_event"
|
||||
| "meteora_dlmm.increase_oracle_length"
|
||||
| "meteora_dlmm.increase_observation_event"
|
||||
| "meteora_dlmm.migrate_bin_array"
|
||||
| "meteora_dlmm.migrate_position"
|
||||
);
|
||||
}
|
||||
|
||||
fn is_meteora_dlmm_admin_event_kind(event_kind: &str) -> bool {
|
||||
if !event_kind.starts_with("meteora_dlmm.") {
|
||||
return false;
|
||||
}
|
||||
if is_meteora_dlmm_pool_lifecycle_event_kind(event_kind) {
|
||||
return false;
|
||||
}
|
||||
return matches!(
|
||||
event_kind,
|
||||
"meteora_dlmm.instruction_audit"
|
||||
| "meteora_dlmm.close_claim_fee_operator_account"
|
||||
| "meteora_dlmm.close_claim_protocol_fee_operator"
|
||||
| "meteora_dlmm.close_operator_account"
|
||||
| "meteora_dlmm.close_preset_parameter"
|
||||
| "meteora_dlmm.close_preset_parameter2"
|
||||
| "meteora_dlmm.close_token_badge"
|
||||
| "meteora_dlmm.create_claim_protocol_fee_operator"
|
||||
| "meteora_dlmm.create_operator_account"
|
||||
| "meteora_dlmm.dynamic_fee_parameter_update_event"
|
||||
| "meteora_dlmm.fee_parameter_update_event"
|
||||
| "meteora_dlmm.initialize_preset_parameter"
|
||||
| "meteora_dlmm.initialize_preset_parameter2"
|
||||
| "meteora_dlmm.initialize_preset_parameter_v2"
|
||||
| "meteora_dlmm.initialize_token_badge"
|
||||
| "meteora_dlmm.set_activation_point"
|
||||
| "meteora_dlmm.set_pair_status"
|
||||
| "meteora_dlmm.set_pair_status_permissionless"
|
||||
| "meteora_dlmm.set_permissionless_operation_bits"
|
||||
| "meteora_dlmm.set_pre_activation_duration"
|
||||
| "meteora_dlmm.set_pre_activation_swap_address"
|
||||
| "meteora_dlmm.update_base_fee_parameters"
|
||||
| "meteora_dlmm.update_dynamic_fee_parameters"
|
||||
| "meteora_dlmm.update_fees_and_reward2"
|
||||
| "meteora_dlmm.update_fees_and_rewards"
|
||||
| "meteora_dlmm.update_reward_duration"
|
||||
| "meteora_dlmm.update_reward_duration_event"
|
||||
| "meteora_dlmm.update_reward_funder"
|
||||
| "meteora_dlmm.update_reward_funder_event"
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns true for liquidity lifecycle changes that must not become candles.
|
||||
pub fn is_dex_liquidity_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.starts_with("meteora_dlmm.")
|
||||
&& (event_kind.contains("withdraw_protocol_fee")
|
||||
|| event_kind.contains("withdraw_ineligible_reward"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if is_meteora_dlmm_position_lifecycle_event_kind(event_kind) {
|
||||
return false;
|
||||
}
|
||||
if event_kind.starts_with("meteora_dlmm.")
|
||||
&& (event_kind == "meteora_dlmm.rebalance_liquidity"
|
||||
|| event_kind == "meteora_dlmm.rebalancing_event"
|
||||
|| event_kind == "meteora_dlmm.remove_all_liquidity")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if event_kind.starts_with("meteora_dbc.")
|
||||
&& (event_kind.contains("fee")
|
||||
|| event_kind.contains("surplus")
|
||||
@@ -461,6 +582,15 @@ pub fn is_dex_liquidity_add_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true for liquidity remove-like DEX events.
|
||||
pub fn is_dex_liquidity_remove_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.starts_with("meteora_dlmm.")
|
||||
&& (event_kind.contains("withdraw_protocol_fee")
|
||||
|| event_kind.contains("withdraw_ineligible_reward"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if event_kind == "meteora_dlmm.remove_all_liquidity" {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".withdraw_pnl") {
|
||||
return false;
|
||||
}
|
||||
@@ -509,6 +639,17 @@ pub fn is_dex_position_close_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true for fee collection events.
|
||||
pub fn is_dex_fee_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.starts_with("meteora_dlmm.") && event_kind.contains("claim_fee_operator") {
|
||||
return false;
|
||||
}
|
||||
if event_kind.starts_with("meteora_dlmm.")
|
||||
&& (event_kind.contains("claim_fee")
|
||||
|| event_kind.contains("composition_fee")
|
||||
|| event_kind.contains("withdraw_protocol_fee")
|
||||
|| event_kind.contains("zap_protocol_fee"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if event_kind.starts_with("meteora_dbc.")
|
||||
&& (event_kind.contains("fee")
|
||||
|| event_kind.contains("surplus")
|
||||
@@ -580,6 +721,13 @@ pub fn is_dex_fee_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true for reward or incentive events.
|
||||
pub fn is_dex_reward_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.starts_with("meteora_dlmm.")
|
||||
&& (event_kind.contains("update_fees_and_reward")
|
||||
|| event_kind.contains("update_reward_duration")
|
||||
|| event_kind.contains("update_reward_funder"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if event_kind.starts_with("pump_fees.")
|
||||
&& (event_kind.contains("social_fee_pda_claimed")
|
||||
|| event_kind.contains("claim_social_fee_pda"))
|
||||
@@ -633,6 +781,15 @@ pub fn is_dex_orderbook_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.contains(".open_limit_order") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".place_limit_order") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".cancel_limit_order") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains("limit_order_evt") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".increase_limit_order") {
|
||||
return true;
|
||||
}
|
||||
@@ -650,6 +807,9 @@ pub fn is_dex_orderbook_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true for pool, pair, launch, mint, burn or migration lifecycle events.
|
||||
pub fn is_dex_pool_lifecycle_event_kind(event_kind: &str) -> bool {
|
||||
if is_meteora_dlmm_pool_lifecycle_event_kind(event_kind) {
|
||||
return true;
|
||||
}
|
||||
if event_kind.starts_with("pump_fees.")
|
||||
&& (event_kind.contains("create_fee_sharing_config")
|
||||
|| event_kind.contains("create_social_fee_pda")
|
||||
@@ -772,6 +932,25 @@ pub fn is_dex_migration_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true for pool creation or initialization events.
|
||||
pub fn is_dex_pool_creation_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind.starts_with("meteora_dlmm.") {
|
||||
if event_kind.contains(".initialize_position") {
|
||||
return false;
|
||||
}
|
||||
if event_kind.contains(".initialize_bin_array") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".initialize_customizable_permissionless_lb_pair")
|
||||
|| event_kind.contains(".initialize_permission_lb_pair")
|
||||
|| event_kind.contains(".initialize_lb_pair")
|
||||
|| event_kind.contains(".lb_pair_create")
|
||||
|| event_kind.contains(".create_pool")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".initialize") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if event_kind == "meteora_dbc.evt_initialize_pool_event"
|
||||
|| event_kind.contains(".initialize_virtual_pool")
|
||||
{
|
||||
@@ -859,6 +1038,12 @@ pub fn is_dex_token_account_close_event_kind(event_kind: &str) -> bool {
|
||||
|
||||
/// Returns true for admin, configuration or permission changes.
|
||||
pub fn is_dex_admin_event_kind(event_kind: &str) -> bool {
|
||||
if is_meteora_dlmm_pool_lifecycle_event_kind(event_kind) {
|
||||
return false;
|
||||
}
|
||||
if is_meteora_dlmm_admin_event_kind(event_kind) {
|
||||
return true;
|
||||
}
|
||||
if event_kind.starts_with("meteora_dbc.")
|
||||
&& (event_kind.contains("config")
|
||||
|| event_kind.contains("operator")
|
||||
@@ -1391,6 +1576,42 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_meteora_dlmm_fee_reward_admin_without_multi_target_overlap() {
|
||||
assert!(super::is_dex_fee_event_kind("meteora_dlmm.withdraw_protocol_fee"));
|
||||
assert!(!super::is_dex_liquidity_event_kind("meteora_dlmm.withdraw_protocol_fee"));
|
||||
assert!(!super::is_dex_liquidity_remove_event_kind("meteora_dlmm.withdraw_protocol_fee"));
|
||||
assert!(!super::is_dex_fee_event_kind("meteora_dlmm.close_claim_fee_operator_account"));
|
||||
assert!(super::is_dex_admin_event_kind("meteora_dlmm.close_claim_fee_operator_account"));
|
||||
assert!(super::is_dex_reward_event_kind("meteora_dlmm.initialize_reward"));
|
||||
assert!(!super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.initialize_reward"));
|
||||
assert!(!super::is_dex_reward_event_kind("meteora_dlmm.update_fees_and_rewards"));
|
||||
assert!(super::is_dex_admin_event_kind("meteora_dlmm.update_fees_and_rewards"));
|
||||
assert!(!super::is_dex_reward_event_kind("meteora_dlmm.update_reward_duration_event"));
|
||||
assert!(super::is_dex_admin_event_kind("meteora_dlmm.update_reward_duration_event"));
|
||||
assert!(super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.position_create_event"));
|
||||
assert!(!super::is_dex_liquidity_event_kind("meteora_dlmm.position_create_event"));
|
||||
assert!(super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.increase_position_length"));
|
||||
assert!(!super::is_dex_liquidity_event_kind("meteora_dlmm.increase_position_length"));
|
||||
assert!(!super::is_dex_admin_event_kind("meteora_dlmm.update_position_operator"));
|
||||
assert!(super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.close_bin_array"));
|
||||
assert!(super::is_dex_admin_event_kind("meteora_dlmm.create_operator_account"));
|
||||
assert!(super::is_dex_admin_event_kind(
|
||||
"meteora_dlmm.initialize_preset_parameter_v2"
|
||||
));
|
||||
assert!(super::is_dex_admin_event_kind("meteora_dlmm.instruction_audit"));
|
||||
assert!(!super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.instruction_audit"));
|
||||
assert!(!super::is_dex_fee_event_kind("meteora_dlmm.instruction_audit"));
|
||||
assert!(!super::is_dex_reward_event_kind("meteora_dlmm.instruction_audit"));
|
||||
assert!(super::is_dex_liquidity_event_kind("meteora_dlmm.rebalancing_event"));
|
||||
assert!(super::is_dex_liquidity_event_kind("meteora_dlmm.remove_all_liquidity"));
|
||||
assert!(!super::is_dex_trade_event_kind("meteora_dlmm.swap_event"));
|
||||
assert!(!super::is_dex_candle_candidate_event_kind("meteora_dlmm.swap_event"));
|
||||
assert!(super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.swap_event"));
|
||||
assert!(!super::is_dex_trade_event_kind("meteora_dlmm.swap2_evt"));
|
||||
assert!(!super::is_dex_candle_candidate_event_kind("meteora_dlmm.swap2_evt"));
|
||||
assert!(super::is_dex_pool_lifecycle_event_kind("meteora_dlmm.swap2_evt"));
|
||||
}
|
||||
#[test]
|
||||
fn enriched_payload_keeps_existing_fields() {
|
||||
let payload_json = serde_json::json!({
|
||||
@@ -1514,6 +1735,10 @@ mod tests {
|
||||
super::classify_dex_event_category_code("meteora_dlmm.remove_liquidity"),
|
||||
"liquidity"
|
||||
);
|
||||
assert_eq!(
|
||||
super::classify_dex_event_category_code("meteora_dlmm.initialize_position"),
|
||||
"pool_lifecycle"
|
||||
);
|
||||
assert_eq!(
|
||||
super::classify_dex_event_lifecycle_kind_code("meteora_dlmm.initialize_position"),
|
||||
"position_open"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -200,6 +200,90 @@ fn resolve_instruction_name(
|
||||
Some(discriminator_hex) => discriminator_hex,
|
||||
None => return None,
|
||||
};
|
||||
if program_id == crate::METEORA_DLMM_PROGRAM_ID || decoder_code == Some("meteora_dlmm") {
|
||||
let name = match discriminator_hex {
|
||||
"e445a52e51cb9a1d" => "anchor_self_cpi_log",
|
||||
"b59d59438fb63448" => "add_liquidity",
|
||||
"e4a24e1c46db7473" => "add_liquidity2",
|
||||
"0703967f94283dc8" => "add_liquidity_by_strategy",
|
||||
"03dd95da6f8d76d5" => "add_liquidity_by_strategy2",
|
||||
"2905eeaf64e106cd" => "add_liquidity_by_strategy_one_side",
|
||||
"1c8cee63e7a21595" => "add_liquidity_by_weight",
|
||||
"d13b3f5b6fc899e4" => "add_liquidity_by_weight2",
|
||||
"5e9b6797465fdca5" => "add_liquidity_one_side",
|
||||
"a1c26754ab47fa9a" => "add_liquidity_one_side_precise",
|
||||
"2133a3c975627de7" => "add_liquidity_one_side_precise2",
|
||||
"849c841f4328e861" => "cancel_limit_order",
|
||||
"a9204f8988e84689" => "claim_fee",
|
||||
"70bf65ab1c907fbb" => "claim_fee2",
|
||||
"955fb5f25e5a9ea2" => "claim_reward",
|
||||
"be037f77b2579db7" => "claim_reward2",
|
||||
"44ae5850b5cc13e0" => "close_bin_array",
|
||||
"b8d5581fb3658224" => "close_claim_fee_operator_account",
|
||||
"397c249b7ef95dab" => "close_limit_order_if_empty",
|
||||
"ab09d54a7817031d" => "close_operator_account",
|
||||
"7b86510031446262" => "close_position",
|
||||
"ae5a2373ba2893e2" => "close_position2",
|
||||
"3b7cd4765b986e9d" => "close_position_if_empty",
|
||||
"04949164861ab53d" => "close_preset_parameter",
|
||||
"27195f6b7411731c" => "close_preset_parameter2",
|
||||
"6c92566eb3fe0a68" => "close_token_badge",
|
||||
"dd40f695f099e5a3" => "create_operator_account",
|
||||
"c2db882019606925" => "decrease_position_length",
|
||||
"b46945505f32496c" => "for_idl_type_generation_do_not_call",
|
||||
"bc32f9a55d97263f" => "fund_reward",
|
||||
"9248aee028fd54ae" => "go_to_a_bin",
|
||||
"be3d7d57674f9ead" => "increase_oracle_length",
|
||||
"505375d3420d2195" => "increase_position_length",
|
||||
"ffd2cc477389e171" => "increase_position_length2",
|
||||
"235613b94ed44bd3" => "initialize_bin_array",
|
||||
"2f9de2b40cf02147" => "initialize_bin_array_bitmap_extension",
|
||||
"2e2729876fb7c840" => "initialize_customizable_permissionless_lb_pair",
|
||||
"f349817e3313f16b" => "initialize_customizable_permissionless_lb_pair2",
|
||||
"2d9aedd2dd0fa65c" => "initialize_lb_pair",
|
||||
"493b2478ed536cc6" => "initialize_lb_pair2",
|
||||
"6c66d555fb033515" => "initialize_permission_lb_pair",
|
||||
"dbc0ea47bebf6650" => "initialize_position",
|
||||
"8f13f291d50f6873" => "initialize_position2",
|
||||
"fbbdbef475fe2394" => "initialize_position_by_operator",
|
||||
"2e527d92558de499" => "initialize_position_pda",
|
||||
"42bc47d3626d0eba" => "initialize_preset_parameter",
|
||||
"75c73e67068e1fcb" => "initialize_preset_parameter_v2",
|
||||
"5f87c0c4f281e644" => "initialize_reward",
|
||||
"fd4dcd5f1be059df" => "initialize_token_badge",
|
||||
"6cb021ba92e501c5" => "place_limit_order",
|
||||
"5c04b0c177b95309" => "rebalance_liquidity",
|
||||
"0a333d2370691855" => "remove_all_liquidity",
|
||||
"5055d14818ceb16c" => "remove_liquidity",
|
||||
"e6d7527ff165e392" => "remove_liquidity2",
|
||||
"1a526698f04a691a" => "remove_liquidity_by_range",
|
||||
"cc02c391359191cd" => "remove_liquidity_by_range2",
|
||||
"5bf90fa51a81fe7d" => "set_activation_point",
|
||||
"43f8e7899a95d9ae" => "set_pair_status",
|
||||
"4e3b98d346b72ed0" => "set_pair_status_permissionless",
|
||||
"543acb8ba351beba" => "set_permissionless_operation_bits",
|
||||
"a53dc9f4829f1664" => "set_pre_activation_duration",
|
||||
"398b2f7bd850df0a" => "set_pre_activation_swap_address",
|
||||
"f8c69e91e17587c8" => "swap",
|
||||
"414b3f4ceb5b5b88" => "swap2",
|
||||
"fa49652126cf4bb8" => "swap_exact_out",
|
||||
"2bd7f784893cf351" => "swap_exact_out2",
|
||||
"38ade6d0ade49ccd" => "swap_with_price_impact",
|
||||
"4a62c0d6b1334b33" => "swap_with_price_impact2",
|
||||
"4ba8dfa110c3032f" => "update_base_fee_parameters",
|
||||
"5ca12ef6ffbd1616" => "update_dynamic_fee_parameters",
|
||||
"208eb89a6741b858" => "update_fees_and_reward2",
|
||||
"9ae6fa0decd14bdf" => "update_fees_and_rewards",
|
||||
"cab8678fb4bf74d9" => "update_position_operator",
|
||||
"8aaec4a9d5ebfe6b" => "update_reward_duration",
|
||||
"d31c3020d7a02317" => "update_reward_funder",
|
||||
"94ce2ac3f7316708" => "withdraw_ineligible_reward",
|
||||
"9ec99ebd215da267" => "withdraw_protocol_fee",
|
||||
"d59bbb2238b65bf0" => "zap_protocol_fee",
|
||||
_ => "instruction_audit",
|
||||
};
|
||||
return Some(format!("meteora_dlmm.{}", name));
|
||||
}
|
||||
if program_id == crate::METEORA_DBC_PROGRAM_ID || decoder_code == Some("meteora_dbc") {
|
||||
let name = match discriminator_hex {
|
||||
"e445a52e51cb9a1d" => "meteora_dbc.anchor_self_cpi_log",
|
||||
@@ -578,6 +662,43 @@ fn option_i64_key(value: std::option::Option<i64>) -> std::string::String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn resolves_meteora_dlmm_instruction_observation_names() {
|
||||
let anchor_name = super::resolve_instruction_name(
|
||||
crate::METEORA_DLMM_PROGRAM_ID,
|
||||
Some("meteora_dlmm"),
|
||||
Some("e445a52e51cb9a1d"),
|
||||
);
|
||||
assert_eq!(anchor_name.as_deref(), Some("meteora_dlmm.anchor_self_cpi_log"));
|
||||
let swap_exact_out2_name = super::resolve_instruction_name(
|
||||
crate::METEORA_DLMM_PROGRAM_ID,
|
||||
Some("meteora_dlmm"),
|
||||
Some("2bd7f784893cf351"),
|
||||
);
|
||||
assert_eq!(swap_exact_out2_name.as_deref(), Some("meteora_dlmm.swap_exact_out2"));
|
||||
let close_position_name = super::resolve_instruction_name(
|
||||
crate::METEORA_DLMM_PROGRAM_ID,
|
||||
Some("meteora_dlmm"),
|
||||
Some("7b86510031446262"),
|
||||
);
|
||||
assert_eq!(close_position_name.as_deref(), Some("meteora_dlmm.close_position"));
|
||||
let preset_v2_name = super::resolve_instruction_name(
|
||||
crate::METEORA_DLMM_PROGRAM_ID,
|
||||
Some("meteora_dlmm"),
|
||||
Some("75c73e67068e1fcb"),
|
||||
);
|
||||
assert_eq!(
|
||||
preset_v2_name.as_deref(),
|
||||
Some("meteora_dlmm.initialize_preset_parameter_v2")
|
||||
);
|
||||
let unknown_name = super::resolve_instruction_name(
|
||||
crate::METEORA_DLMM_PROGRAM_ID,
|
||||
Some("meteora_dlmm"),
|
||||
Some("ffffffffffffffff"),
|
||||
);
|
||||
assert_eq!(unknown_name.as_deref(), Some("meteora_dlmm.instruction_audit"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_meteora_dbc_instruction_observation_names() {
|
||||
let anchor_name = super::resolve_instruction_name(
|
||||
|
||||
@@ -71,10 +71,14 @@ fn should_skip_non_trade_event_due_to_explicit_reason(
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if crate::is_dex_orderbook_event_kind(decoded_event.event_kind.as_str())
|
||||
&& payload_has_non_empty_text(payload, "skipOrderbookReason")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
fn should_attempt_meteora_dbc_explicit_skip_materialization(
|
||||
decoded_event: &crate::DexDecodedEventDto,
|
||||
payload: &serde_json::Value,
|
||||
@@ -121,7 +125,6 @@ fn is_meteora_dbc_instruction_admin_materialization_candidate(event_kind: &str)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum FeeAmountRecoveryPolicy {
|
||||
Disabled,
|
||||
@@ -151,11 +154,43 @@ fn fee_amount_recovery_policy_for_event_kind(event_kind: &str) -> FeeAmountRecov
|
||||
| "raydium_launchpad.claim_platform_fee_from_vault"
|
||||
| "raydium_launchpad.collect_fee"
|
||||
| "raydium_stable_swap.withdraw_pnl"
|
||||
| "raydium_stable_swap.withdraw_srm" => FeeAmountRecoveryPolicy::InnerSplTransfer,
|
||||
| "raydium_stable_swap.withdraw_srm"
|
||||
| "meteora_dlmm.claim_fee"
|
||||
| "meteora_dlmm.claim_fee2"
|
||||
| "meteora_dlmm.claim_fee_event"
|
||||
| "meteora_dlmm.claim_fee2_event"
|
||||
| "meteora_dlmm.composition_fee_event"
|
||||
| "meteora_dlmm.withdraw_protocol_fee"
|
||||
| "meteora_dlmm.zap_protocol_fee" => FeeAmountRecoveryPolicy::InnerSplTransfer,
|
||||
_ => FeeAmountRecoveryPolicy::Disabled,
|
||||
};
|
||||
}
|
||||
|
||||
fn reward_amount_recovery_policy_for_event_kind(event_kind: &str) -> FeeAmountRecoveryPolicy {
|
||||
return match event_kind {
|
||||
"meteora_dlmm.claim_reward"
|
||||
| "meteora_dlmm.claim_reward2"
|
||||
| "meteora_dlmm.claim_reward_event"
|
||||
| "meteora_dlmm.claim_reward2_event"
|
||||
| "meteora_dlmm.fund_reward"
|
||||
| "meteora_dlmm.fund_reward_event"
|
||||
| "meteora_dlmm.initialize_reward"
|
||||
| "meteora_dlmm.initialize_reward_event"
|
||||
| "meteora_dlmm.withdraw_ineligible_reward"
|
||||
| "meteora_dlmm.withdraw_ineligible_reward_event" => {
|
||||
FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
},
|
||||
_ => FeeAmountRecoveryPolicy::Disabled,
|
||||
};
|
||||
}
|
||||
|
||||
fn optional_text_is_missing(value: &std::option::Option<std::string::String>) -> bool {
|
||||
match value.as_ref() {
|
||||
Some(value) => return value.trim().is_empty(),
|
||||
None => return true,
|
||||
}
|
||||
}
|
||||
|
||||
fn payload_has_non_empty_text(payload: &serde_json::Value, key: &str) -> bool {
|
||||
let value = match payload.get(key) {
|
||||
Some(value) => value,
|
||||
@@ -240,7 +275,10 @@ impl NonTradeEventMaterializationService {
|
||||
continue;
|
||||
}
|
||||
if should_skip_non_trade_event_due_to_explicit_reason(decoded_event, &payload)
|
||||
&& !should_attempt_meteora_dbc_explicit_skip_materialization(decoded_event, &payload)
|
||||
&& !should_attempt_meteora_dbc_explicit_skip_materialization(
|
||||
decoded_event,
|
||||
&payload,
|
||||
)
|
||||
{
|
||||
tracing::debug!(
|
||||
event_kind = %decoded_event.event_kind,
|
||||
@@ -534,10 +572,44 @@ impl NonTradeEventMaterializationService {
|
||||
],
|
||||
);
|
||||
let mut payload_json = decoded_event.payload_json.clone();
|
||||
let mut fee_amount_legs: std::vec::Vec<MeteoraDbcActualAmount> = std::vec::Vec::new();
|
||||
if is_meteora_dbc_instruction_fee_materialization_candidate(decoded_event.event_kind.as_str()) {
|
||||
let mut fee_amount_legs: std::vec::Vec<MeteoraDbcActualAmount> =
|
||||
fee_amount_legs_from_payload(payload);
|
||||
if !fee_amount_legs.is_empty() {
|
||||
match fee_amount_legs.as_slice() {
|
||||
[first_leg] => {
|
||||
fee_token_mint = Some(first_leg.token_mint.clone());
|
||||
fee_amount_raw = Some(first_leg.amount_raw.clone());
|
||||
},
|
||||
_ => {
|
||||
fee_token_mint = None;
|
||||
fee_amount_raw = None;
|
||||
},
|
||||
}
|
||||
let updated_payload =
|
||||
decoded_payload_with_materialized_fee_legs(payload, &fee_amount_legs);
|
||||
payload_json = updated_payload.to_string();
|
||||
let update_result = crate::query_dex_decoded_events_update_payload_json_by_id(
|
||||
self.database.as_ref(),
|
||||
decoded_event_id,
|
||||
payload_json.as_str(),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = update_result {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if fee_amount_legs.is_empty()
|
||||
&& is_meteora_dbc_instruction_fee_materialization_candidate(
|
||||
decoded_event.event_kind.as_str(),
|
||||
)
|
||||
{
|
||||
let inferred_result = self
|
||||
.resolve_meteora_dbc_actual_fee_amounts(transaction, transaction_id, decoded_event, payload)
|
||||
.resolve_meteora_dbc_actual_fee_amounts(
|
||||
transaction,
|
||||
transaction_id,
|
||||
decoded_event,
|
||||
payload,
|
||||
)
|
||||
.await;
|
||||
let inferred = match inferred_result {
|
||||
Ok(inferred) => inferred,
|
||||
@@ -555,7 +627,8 @@ impl NonTradeEventMaterializationService {
|
||||
fee_amount_raw = None;
|
||||
},
|
||||
}
|
||||
let updated_payload = decoded_payload_with_materialized_fee_legs(payload, &fee_amount_legs);
|
||||
let updated_payload =
|
||||
decoded_payload_with_materialized_fee_legs(payload, &fee_amount_legs);
|
||||
payload_json = updated_payload.to_string();
|
||||
let update_result = crate::query_dex_decoded_events_update_payload_json_by_id(
|
||||
self.database.as_ref(),
|
||||
@@ -597,11 +670,14 @@ impl NonTradeEventMaterializationService {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
let recovery_policy = fee_amount_recovery_policy_for_event_kind(decoded_event.event_kind.as_str());
|
||||
let recovery_policy =
|
||||
fee_amount_recovery_policy_for_event_kind(decoded_event.event_kind.as_str());
|
||||
if fee_amount_legs.is_empty()
|
||||
&& fee_amount_raw.is_none()
|
||||
&& recovery_policy != FeeAmountRecoveryPolicy::Disabled
|
||||
&& !is_meteora_dbc_instruction_fee_materialization_candidate(decoded_event.event_kind.as_str())
|
||||
&& !is_meteora_dbc_instruction_fee_materialization_candidate(
|
||||
decoded_event.event_kind.as_str(),
|
||||
)
|
||||
{
|
||||
let inferred_result = self
|
||||
.resolve_allowlisted_actual_fee_amounts_from_spl_transfers(
|
||||
@@ -626,7 +702,8 @@ impl NonTradeEventMaterializationService {
|
||||
fee_amount_raw = None;
|
||||
},
|
||||
}
|
||||
let updated_payload = decoded_payload_with_materialized_fee_legs(payload, &fee_amount_legs);
|
||||
let updated_payload =
|
||||
decoded_payload_with_materialized_fee_legs(payload, &fee_amount_legs);
|
||||
payload_json = updated_payload.to_string();
|
||||
let update_result = crate::query_dex_decoded_events_update_payload_json_by_id(
|
||||
self.database.as_ref(),
|
||||
@@ -650,7 +727,8 @@ impl NonTradeEventMaterializationService {
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
if let Some(explanation) = explanation {
|
||||
let updated_payload = decoded_payload_with_unmaterialized_fee_amount_recovery_reason(
|
||||
let updated_payload =
|
||||
decoded_payload_with_unmaterialized_fee_amount_recovery_reason(
|
||||
payload,
|
||||
explanation.as_str(),
|
||||
);
|
||||
@@ -781,9 +859,12 @@ impl NonTradeEventMaterializationService {
|
||||
Some(_) => extract_first_i64(payload, &["instructionId", "instruction_id"]),
|
||||
None => None,
|
||||
};
|
||||
let instruction_index = extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result =
|
||||
crate::query_chain_instructions_list_by_transaction_id(self.database.as_ref(), transaction_id)
|
||||
let instruction_index =
|
||||
extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result = crate::query_chain_instructions_list_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
)
|
||||
.await;
|
||||
let instructions = match instructions_result {
|
||||
Ok(instructions) => instructions,
|
||||
@@ -855,9 +936,12 @@ impl NonTradeEventMaterializationService {
|
||||
Some(_) => extract_first_i64(payload, &["instructionId", "instruction_id"]),
|
||||
None => None,
|
||||
};
|
||||
let instruction_index = extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result =
|
||||
crate::query_chain_instructions_list_by_transaction_id(self.database.as_ref(), transaction_id)
|
||||
let instruction_index =
|
||||
extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result = crate::query_chain_instructions_list_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
)
|
||||
.await;
|
||||
let instructions = match instructions_result {
|
||||
Ok(instructions) => instructions,
|
||||
@@ -929,9 +1013,12 @@ impl NonTradeEventMaterializationService {
|
||||
Some(_) => extract_first_i64(payload, &["instructionId", "instruction_id"]),
|
||||
None => None,
|
||||
};
|
||||
let instruction_index = extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result =
|
||||
crate::query_chain_instructions_list_by_transaction_id(self.database.as_ref(), transaction_id)
|
||||
let instruction_index =
|
||||
extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result = crate::query_chain_instructions_list_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
)
|
||||
.await;
|
||||
let instructions = match instructions_result {
|
||||
Ok(instructions) => instructions,
|
||||
@@ -988,9 +1075,7 @@ impl NonTradeEventMaterializationService {
|
||||
non_zero_mints.insert(mint);
|
||||
}
|
||||
if non_zero_mints.len() > 1 {
|
||||
return Ok(Some(
|
||||
"multi_token_fee_amounts_materialized_as_fee_amount_legs".to_string(),
|
||||
));
|
||||
return Ok(Some("multi_token_fee_amounts_materialized_as_fee_amount_legs".to_string()));
|
||||
}
|
||||
if transfer_count > 0 && non_zero_transfer_count == 0 {
|
||||
return Ok(Some("fee_instruction_has_only_zero_amount_transfers".to_string()));
|
||||
@@ -1001,6 +1086,86 @@ impl NonTradeEventMaterializationService {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
async fn resolve_allowlisted_actual_reward_amount_from_spl_transfers(
|
||||
&self,
|
||||
transaction_id: i64,
|
||||
decoded_event: &crate::DexDecodedEventDto,
|
||||
payload: &serde_json::Value,
|
||||
) -> Result<std::option::Option<MeteoraDbcActualAmount>, crate::Error> {
|
||||
let parent_instruction_id = match decoded_event.id {
|
||||
Some(_) => extract_first_i64(payload, &["instructionId", "instruction_id"]),
|
||||
None => None,
|
||||
};
|
||||
let instruction_index =
|
||||
extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result = crate::query_chain_instructions_list_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
)
|
||||
.await;
|
||||
let instructions = match instructions_result {
|
||||
Ok(instructions) => instructions,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let mut amount_legs = std::vec::Vec::new();
|
||||
for instruction in &instructions {
|
||||
if !instruction_is_child_of_decoded_event(
|
||||
instruction,
|
||||
parent_instruction_id,
|
||||
instruction_index,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
let parsed_type = match instruction.parsed_type.as_deref() {
|
||||
Some(parsed_type) => parsed_type,
|
||||
None => continue,
|
||||
};
|
||||
if parsed_type != "transferChecked" && parsed_type != "transfer" {
|
||||
continue;
|
||||
}
|
||||
let parsed_json = match instruction.parsed_json.as_deref() {
|
||||
Some(parsed_json) => parsed_json,
|
||||
None => continue,
|
||||
};
|
||||
let parsed_value = serde_json::from_str::<serde_json::Value>(parsed_json);
|
||||
let parsed_value = match parsed_value {
|
||||
Ok(parsed_value) => parsed_value,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let amount_raw = extract_spl_transfer_amount_raw(&parsed_value);
|
||||
let amount_raw = match amount_raw {
|
||||
Some(amount_raw) => amount_raw,
|
||||
None => continue,
|
||||
};
|
||||
let amount = amount_raw.parse::<u128>();
|
||||
let amount = match amount {
|
||||
Ok(amount) => amount,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if amount == 0 {
|
||||
continue;
|
||||
}
|
||||
let mint = extract_first_string(&parsed_value, &["mint"]);
|
||||
let mint = match mint {
|
||||
Some(mint) => mint,
|
||||
None => continue,
|
||||
};
|
||||
let source_account = extract_first_string(&parsed_value, &["source"]);
|
||||
let destination_account = extract_first_string(&parsed_value, &["destination"]);
|
||||
amount_legs.push(MeteoraDbcActualAmount {
|
||||
token_mint: mint,
|
||||
amount_raw,
|
||||
source: "allowlisted_reward_inner_spl_transfer".to_string(),
|
||||
source_account,
|
||||
destination_account,
|
||||
});
|
||||
}
|
||||
return Ok(single_mint_amount_from_actual_amounts(
|
||||
amount_legs.as_slice(),
|
||||
"allowlisted_reward_inner_spl_transfer",
|
||||
));
|
||||
}
|
||||
|
||||
async fn resolve_meteora_dbc_unmaterialized_fee_skip_reason(
|
||||
&self,
|
||||
transaction_id: i64,
|
||||
@@ -1011,9 +1176,12 @@ impl NonTradeEventMaterializationService {
|
||||
Some(_) => extract_first_i64(payload, &["instructionId", "instruction_id"]),
|
||||
None => None,
|
||||
};
|
||||
let instruction_index = extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result =
|
||||
crate::query_chain_instructions_list_by_transaction_id(self.database.as_ref(), transaction_id)
|
||||
let instruction_index =
|
||||
extract_first_i64(payload, &["instructionIndex", "instruction_index"]);
|
||||
let instructions_result = crate::query_chain_instructions_list_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
)
|
||||
.await;
|
||||
let instructions = match instructions_result {
|
||||
Ok(instructions) => instructions,
|
||||
@@ -1070,9 +1238,7 @@ impl NonTradeEventMaterializationService {
|
||||
non_zero_mints.insert(mint);
|
||||
}
|
||||
if non_zero_mints.len() > 1 {
|
||||
return Ok(Some(
|
||||
"multi_token_fee_amounts_require_multiple_fee_rows".to_string(),
|
||||
));
|
||||
return Ok(Some("multi_token_fee_amounts_require_multiple_fee_rows".to_string()));
|
||||
}
|
||||
if transfer_count > 0 && non_zero_transfer_count == 0 {
|
||||
return Ok(Some("fee_instruction_has_only_zero_amount_transfers".to_string()));
|
||||
@@ -1112,11 +1278,11 @@ impl NonTradeEventMaterializationService {
|
||||
"user",
|
||||
],
|
||||
);
|
||||
let reward_token_mint = extract_first_string(
|
||||
let mut reward_token_mint = extract_first_string(
|
||||
payload,
|
||||
&["rewardTokenMint", "reward_token_mint", "tokenMint", "token_mint", "mint"],
|
||||
);
|
||||
let reward_amount_raw = extract_first_amount_string(
|
||||
let mut reward_amount_raw = extract_first_amount_string(
|
||||
payload,
|
||||
&[
|
||||
"rewardAmountRaw",
|
||||
@@ -1128,6 +1294,35 @@ impl NonTradeEventMaterializationService {
|
||||
"amount",
|
||||
],
|
||||
);
|
||||
let mut reward_payload_json = decoded_event.payload_json.clone();
|
||||
if reward_amount_recovery_policy_for_event_kind(decoded_event.event_kind.as_str())
|
||||
== FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
&& (optional_text_is_missing(&reward_token_mint)
|
||||
|| optional_text_is_missing(&reward_amount_raw))
|
||||
{
|
||||
let recovered_reward_result = self
|
||||
.resolve_allowlisted_actual_reward_amount_from_spl_transfers(
|
||||
transaction_id,
|
||||
decoded_event,
|
||||
payload,
|
||||
)
|
||||
.await;
|
||||
let recovered_reward = match recovered_reward_result {
|
||||
Ok(recovered_reward) => recovered_reward,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
if let Some(recovered_reward) = recovered_reward {
|
||||
if optional_text_is_missing(&reward_token_mint) {
|
||||
reward_token_mint = Some(recovered_reward.token_mint.clone());
|
||||
}
|
||||
if optional_text_is_missing(&reward_amount_raw) {
|
||||
reward_amount_raw = Some(recovered_reward.amount_raw.clone());
|
||||
}
|
||||
reward_payload_json =
|
||||
decoded_payload_with_materialized_reward_amount(payload, &recovered_reward)
|
||||
.to_string();
|
||||
}
|
||||
}
|
||||
let dto = crate::RewardEventDto::new(
|
||||
transaction_id,
|
||||
Some(decoded_event_id),
|
||||
@@ -1143,7 +1338,7 @@ impl NonTradeEventMaterializationService {
|
||||
actor_wallet,
|
||||
reward_token_mint,
|
||||
reward_amount_raw,
|
||||
decoded_event.payload_json.clone(),
|
||||
reward_payload_json,
|
||||
);
|
||||
let upsert_result = crate::query_reward_events_upsert(self.database.as_ref(), &dto).await;
|
||||
match upsert_result {
|
||||
@@ -2100,6 +2295,119 @@ struct MeteoraDbcActualAmount {
|
||||
destination_account: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
fn single_mint_amount_from_actual_amounts(
|
||||
amount_legs: &[MeteoraDbcActualAmount],
|
||||
source: &str,
|
||||
) -> std::option::Option<MeteoraDbcActualAmount> {
|
||||
let mut token_mint: std::option::Option<std::string::String> = None;
|
||||
let mut amount_total: u128 = 0;
|
||||
let mut source_account: std::option::Option<std::string::String> = None;
|
||||
let mut destination_account: std::option::Option<std::string::String> = None;
|
||||
for leg in amount_legs {
|
||||
if leg.token_mint.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
let amount = leg.amount_raw.parse::<u128>();
|
||||
let amount = match amount {
|
||||
Ok(amount) => amount,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if amount == 0 {
|
||||
continue;
|
||||
}
|
||||
match token_mint.as_ref() {
|
||||
Some(existing_mint) => {
|
||||
if existing_mint != &leg.token_mint {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
None => token_mint = Some(leg.token_mint.clone()),
|
||||
}
|
||||
let checked_total = amount_total.checked_add(amount);
|
||||
amount_total = match checked_total {
|
||||
Some(checked_total) => checked_total,
|
||||
None => return None,
|
||||
};
|
||||
if source_account.is_none() {
|
||||
source_account = leg.source_account.clone();
|
||||
}
|
||||
if destination_account.is_none() {
|
||||
destination_account = leg.destination_account.clone();
|
||||
}
|
||||
}
|
||||
let token_mint = match token_mint {
|
||||
Some(token_mint) => token_mint,
|
||||
None => return None,
|
||||
};
|
||||
if amount_total == 0 {
|
||||
return None;
|
||||
}
|
||||
return Some(MeteoraDbcActualAmount {
|
||||
token_mint,
|
||||
amount_raw: amount_total.to_string(),
|
||||
source: source.to_string(),
|
||||
source_account,
|
||||
destination_account,
|
||||
});
|
||||
}
|
||||
|
||||
fn fee_amount_legs_from_payload(
|
||||
payload: &serde_json::Value,
|
||||
) -> std::vec::Vec<MeteoraDbcActualAmount> {
|
||||
let mut legs = std::vec::Vec::new();
|
||||
let candidate_arrays = ["feeAmountLegs", "materializedFeeAmountLegs"];
|
||||
for candidate_key in candidate_arrays {
|
||||
let candidate = match payload.get(candidate_key) {
|
||||
Some(candidate) => candidate,
|
||||
None => continue,
|
||||
};
|
||||
let array = match candidate.as_array() {
|
||||
Some(array) => array,
|
||||
None => continue,
|
||||
};
|
||||
for leg_value in array {
|
||||
let token_mint = extract_first_string(
|
||||
leg_value,
|
||||
&["tokenMint", "token_mint", "feeTokenMint", "fee_token_mint", "mint"],
|
||||
);
|
||||
let amount_raw = extract_first_amount_string(
|
||||
leg_value,
|
||||
&["amountRaw", "amount_raw", "feeAmountRaw", "fee_amount_raw", "amount"],
|
||||
);
|
||||
let token_mint = match token_mint {
|
||||
Some(token_mint) => token_mint,
|
||||
None => continue,
|
||||
};
|
||||
let amount_raw = match amount_raw {
|
||||
Some(amount_raw) => amount_raw,
|
||||
None => continue,
|
||||
};
|
||||
let amount_trimmed = amount_raw.trim();
|
||||
if amount_trimmed.is_empty() || amount_trimmed == "0" {
|
||||
continue;
|
||||
}
|
||||
let source =
|
||||
match extract_first_string(leg_value, &["amountSource", "amount_source", "source"])
|
||||
{
|
||||
Some(source) => source,
|
||||
None => "decoded_fee_amount_leg".to_string(),
|
||||
};
|
||||
let source_account =
|
||||
extract_first_string(leg_value, &["sourceAccount", "source_account"]);
|
||||
let destination_account =
|
||||
extract_first_string(leg_value, &["destinationAccount", "destination_account"]);
|
||||
legs.push(MeteoraDbcActualAmount {
|
||||
token_mint,
|
||||
amount_raw: amount_trimmed.to_string(),
|
||||
source,
|
||||
source_account,
|
||||
destination_account,
|
||||
});
|
||||
}
|
||||
}
|
||||
return legs;
|
||||
}
|
||||
|
||||
fn instruction_is_child_of_decoded_event(
|
||||
instruction: &crate::ChainInstructionDto,
|
||||
parent_instruction_id: std::option::Option<i64>,
|
||||
@@ -2147,6 +2455,57 @@ fn extract_spl_transfer_amount_raw(
|
||||
return None;
|
||||
}
|
||||
|
||||
fn decoded_payload_with_materialized_reward_amount(
|
||||
payload: &serde_json::Value,
|
||||
reward_amount: &MeteoraDbcActualAmount,
|
||||
) -> serde_json::Value {
|
||||
let mut object = match payload.clone() {
|
||||
serde_json::Value::Object(object) => object,
|
||||
other => {
|
||||
let mut object = serde_json::Map::new();
|
||||
object.insert("rawPayload".to_string(), other);
|
||||
object
|
||||
},
|
||||
};
|
||||
object.insert("skipRewardReason".to_string(), serde_json::Value::String(String::new()));
|
||||
object.insert("rewardMaterialized".to_string(), serde_json::Value::Bool(true));
|
||||
object.insert(
|
||||
"rewardMaterializationSource".to_string(),
|
||||
serde_json::Value::String(reward_amount.source.clone()),
|
||||
);
|
||||
object.insert(
|
||||
"rewardTokenMint".to_string(),
|
||||
serde_json::Value::String(reward_amount.token_mint.clone()),
|
||||
);
|
||||
object.insert(
|
||||
"rewardAmountRaw".to_string(),
|
||||
serde_json::Value::String(reward_amount.amount_raw.clone()),
|
||||
);
|
||||
match reward_amount.source_account.as_ref() {
|
||||
Some(source_account) => {
|
||||
object.insert(
|
||||
"rewardSourceAccount".to_string(),
|
||||
serde_json::Value::String(source_account.clone()),
|
||||
);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
match reward_amount.destination_account.as_ref() {
|
||||
Some(destination_account) => {
|
||||
object.insert(
|
||||
"rewardDestinationAccount".to_string(),
|
||||
serde_json::Value::String(destination_account.clone()),
|
||||
);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
object.insert(
|
||||
"eventActionability".to_string(),
|
||||
serde_json::Value::String("reward_materialized".to_string()),
|
||||
);
|
||||
return serde_json::Value::Object(object);
|
||||
}
|
||||
|
||||
fn decoded_payload_with_materialized_fee_legs(
|
||||
payload: &serde_json::Value,
|
||||
legs: &[MeteoraDbcActualAmount],
|
||||
@@ -2159,11 +2518,11 @@ fn decoded_payload_with_materialized_fee_legs(
|
||||
object
|
||||
},
|
||||
};
|
||||
object.insert("skipFeeReason".to_string(), serde_json::Value::String(std::string::String::new()));
|
||||
object.insert(
|
||||
"feeMaterialized".to_string(),
|
||||
serde_json::Value::Bool(true),
|
||||
"skipFeeReason".to_string(),
|
||||
serde_json::Value::String(std::string::String::new()),
|
||||
);
|
||||
object.insert("feeMaterialized".to_string(), serde_json::Value::Bool(true));
|
||||
object.insert(
|
||||
"feeMaterializationSource".to_string(),
|
||||
serde_json::Value::String("fee_event_amounts".to_string()),
|
||||
@@ -2217,18 +2576,9 @@ fn fee_amount_leg_payload_json(
|
||||
"legIndex".to_string(),
|
||||
serde_json::Value::Number(serde_json::Number::from(u64::from(leg_index))),
|
||||
);
|
||||
object.insert(
|
||||
"tokenMint".to_string(),
|
||||
serde_json::Value::String(leg.token_mint.clone()),
|
||||
);
|
||||
object.insert(
|
||||
"amountRaw".to_string(),
|
||||
serde_json::Value::String(leg.amount_raw.clone()),
|
||||
);
|
||||
object.insert(
|
||||
"amountSource".to_string(),
|
||||
serde_json::Value::String(leg.source.clone()),
|
||||
);
|
||||
object.insert("tokenMint".to_string(), serde_json::Value::String(leg.token_mint.clone()));
|
||||
object.insert("amountRaw".to_string(), serde_json::Value::String(leg.amount_raw.clone()));
|
||||
object.insert("amountSource".to_string(), serde_json::Value::String(leg.source.clone()));
|
||||
match leg.source_account.as_ref() {
|
||||
Some(source_account) => {
|
||||
object.insert(
|
||||
@@ -2250,7 +2600,6 @@ fn fee_amount_leg_payload_json(
|
||||
return serde_json::Value::Object(object).to_string();
|
||||
}
|
||||
|
||||
|
||||
fn fee_event_amount_leg_from_parent_amount(
|
||||
decoded_event: &crate::DexDecodedEventDto,
|
||||
transaction_id: i64,
|
||||
@@ -2272,7 +2621,11 @@ fn fee_event_amount_leg_from_parent_amount(
|
||||
if fee_amount_raw.trim().is_empty() {
|
||||
return None;
|
||||
}
|
||||
let payload_json = fee_amount_parent_payload_json(decoded_event, fee_token_mint.as_str(), fee_amount_raw.as_str());
|
||||
let payload_json = fee_amount_parent_payload_json(
|
||||
decoded_event,
|
||||
fee_token_mint.as_str(),
|
||||
fee_amount_raw.as_str(),
|
||||
);
|
||||
return Some(crate::FeeEventAmountDto::new(
|
||||
0,
|
||||
transaction_id,
|
||||
@@ -2302,14 +2655,8 @@ fn fee_amount_parent_payload_json(
|
||||
"legIndex".to_string(),
|
||||
serde_json::Value::Number(serde_json::Number::from(0_u64)),
|
||||
);
|
||||
object.insert(
|
||||
"tokenMint".to_string(),
|
||||
serde_json::Value::String(token_mint.to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"amountRaw".to_string(),
|
||||
serde_json::Value::String(amount_raw.to_string()),
|
||||
);
|
||||
object.insert("tokenMint".to_string(), serde_json::Value::String(token_mint.to_string()));
|
||||
object.insert("amountRaw".to_string(), serde_json::Value::String(amount_raw.to_string()));
|
||||
object.insert(
|
||||
"amountSource".to_string(),
|
||||
serde_json::Value::String("parent_fee_event_amount".to_string()),
|
||||
@@ -2329,14 +2676,8 @@ fn decoded_payload_with_unmaterialized_fee_reason(
|
||||
object
|
||||
},
|
||||
};
|
||||
object.insert(
|
||||
"skipFeeReason".to_string(),
|
||||
serde_json::Value::String(reason.to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"feeMaterialized".to_string(),
|
||||
serde_json::Value::Bool(false),
|
||||
);
|
||||
object.insert("skipFeeReason".to_string(), serde_json::Value::String(reason.to_string()));
|
||||
object.insert("feeMaterialized".to_string(), serde_json::Value::Bool(false));
|
||||
object.insert(
|
||||
"feeMaterializationSource".to_string(),
|
||||
serde_json::Value::String("none".to_string()),
|
||||
@@ -2368,10 +2709,7 @@ fn decoded_payload_with_unmaterialized_fee_amount_recovery_reason(
|
||||
"feeAmountRecoveryReason".to_string(),
|
||||
serde_json::Value::String(reason.to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"feeAmountLegsMaterialized".to_string(),
|
||||
serde_json::Value::Bool(false),
|
||||
);
|
||||
object.insert("feeAmountLegsMaterialized".to_string(), serde_json::Value::Bool(false));
|
||||
object.insert(
|
||||
"feeAmountLegCount".to_string(),
|
||||
serde_json::Value::Number(serde_json::Number::from(0_u64)),
|
||||
@@ -2387,7 +2725,8 @@ fn resolve_meteora_dbc_actual_fee_amount_from_lamport_delta(
|
||||
if !decoded_event.event_kind.contains("pool_creation_fee") {
|
||||
return None;
|
||||
}
|
||||
let transaction_value = serde_json::from_str::<serde_json::Value>(transaction.transaction_json.as_str());
|
||||
let transaction_value =
|
||||
serde_json::from_str::<serde_json::Value>(transaction.transaction_json.as_str());
|
||||
let transaction_value = match transaction_value {
|
||||
Ok(transaction_value) => transaction_value,
|
||||
Err(_) => return None,
|
||||
@@ -2408,7 +2747,8 @@ fn resolve_meteora_dbc_actual_fee_amount_from_lamport_delta(
|
||||
append_unique_candidate_account(&mut candidate_accounts, decoded_event.pool_account.as_deref());
|
||||
let payload_pool_account = extract_first_string(payload, &["poolAccount", "pool", "poolState"]);
|
||||
append_unique_candidate_account(&mut candidate_accounts, payload_pool_account.as_deref());
|
||||
let payload_related_account = extract_first_string(payload, &["relatedAccount", "receiver", "feeReceiver"]);
|
||||
let payload_related_account =
|
||||
extract_first_string(payload, &["relatedAccount", "receiver", "feeReceiver"]);
|
||||
append_unique_candidate_account(&mut candidate_accounts, payload_related_account.as_deref());
|
||||
if let Some(accounts) = payload.get("accounts").and_then(serde_json::Value::as_array) {
|
||||
for account in accounts {
|
||||
@@ -3325,6 +3665,155 @@ mod tests {
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dbc.claim_trading_fee"),
|
||||
super::FeeAmountRecoveryPolicy::Disabled
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dlmm.claim_fee"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dlmm.claim_fee2"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dlmm.composition_fee_event"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dlmm.withdraw_protocol_fee"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dlmm.zap_protocol_fee"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind(
|
||||
"meteora_dlmm.close_claim_fee_operator_account"
|
||||
),
|
||||
super::FeeAmountRecoveryPolicy::Disabled
|
||||
);
|
||||
assert_eq!(
|
||||
super::fee_amount_recovery_policy_for_event_kind("meteora_dlmm.swap_event"),
|
||||
super::FeeAmountRecoveryPolicy::Disabled
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reward_amount_recovery_policy_is_allowlisted_only() {
|
||||
assert_eq!(
|
||||
super::reward_amount_recovery_policy_for_event_kind("meteora_dlmm.claim_reward"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::reward_amount_recovery_policy_for_event_kind("meteora_dlmm.claim_reward2"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::reward_amount_recovery_policy_for_event_kind("meteora_dlmm.claim_reward_event"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::reward_amount_recovery_policy_for_event_kind("meteora_dlmm.fund_reward"),
|
||||
super::FeeAmountRecoveryPolicy::InnerSplTransfer
|
||||
);
|
||||
assert_eq!(
|
||||
super::reward_amount_recovery_policy_for_event_kind(
|
||||
"meteora_dlmm.update_fees_and_rewards"
|
||||
),
|
||||
super::FeeAmountRecoveryPolicy::Disabled
|
||||
);
|
||||
assert_eq!(
|
||||
super::reward_amount_recovery_policy_for_event_kind("meteora_dlmm.swap_event"),
|
||||
super::FeeAmountRecoveryPolicy::Disabled
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_mint_reward_amount_sums_matching_mints_only() {
|
||||
let legs = vec![
|
||||
super::MeteoraDbcActualAmount {
|
||||
token_mint: "RewardMint111".to_string(),
|
||||
amount_raw: "7".to_string(),
|
||||
source: "test".to_string(),
|
||||
source_account: Some("Source111".to_string()),
|
||||
destination_account: Some("Destination111".to_string()),
|
||||
},
|
||||
super::MeteoraDbcActualAmount {
|
||||
token_mint: "RewardMint111".to_string(),
|
||||
amount_raw: "5".to_string(),
|
||||
source: "test".to_string(),
|
||||
source_account: Some("Source222".to_string()),
|
||||
destination_account: Some("Destination222".to_string()),
|
||||
},
|
||||
];
|
||||
let resolved = super::single_mint_amount_from_actual_amounts(
|
||||
legs.as_slice(),
|
||||
"allowlisted_reward_inner_spl_transfer",
|
||||
);
|
||||
let resolved = match resolved {
|
||||
Some(resolved) => resolved,
|
||||
None => panic!("expected single mint reward amount"),
|
||||
};
|
||||
assert_eq!(resolved.token_mint, "RewardMint111");
|
||||
assert_eq!(resolved.amount_raw, "12");
|
||||
assert_eq!(resolved.source, "allowlisted_reward_inner_spl_transfer");
|
||||
|
||||
let mixed_mint_legs = vec![
|
||||
super::MeteoraDbcActualAmount {
|
||||
token_mint: "RewardMint111".to_string(),
|
||||
amount_raw: "7".to_string(),
|
||||
source: "test".to_string(),
|
||||
source_account: None,
|
||||
destination_account: None,
|
||||
},
|
||||
super::MeteoraDbcActualAmount {
|
||||
token_mint: "OtherMint111".to_string(),
|
||||
amount_raw: "5".to_string(),
|
||||
source: "test".to_string(),
|
||||
source_account: None,
|
||||
destination_account: None,
|
||||
},
|
||||
];
|
||||
assert!(
|
||||
super::single_mint_amount_from_actual_amounts(
|
||||
mixed_mint_legs.as_slice(),
|
||||
"allowlisted_reward_inner_spl_transfer",
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoded_payload_with_materialized_reward_amount_marks_source() {
|
||||
let payload = serde_json::json!({
|
||||
"eventKind": "meteora_dlmm.claim_reward"
|
||||
});
|
||||
let reward_amount = super::MeteoraDbcActualAmount {
|
||||
token_mint: "RewardMint111".to_string(),
|
||||
amount_raw: "42".to_string(),
|
||||
source: "allowlisted_reward_inner_spl_transfer".to_string(),
|
||||
source_account: Some("Source111".to_string()),
|
||||
destination_account: Some("Destination111".to_string()),
|
||||
};
|
||||
let materialized =
|
||||
super::decoded_payload_with_materialized_reward_amount(&payload, &reward_amount);
|
||||
assert_eq!(
|
||||
materialized.get("rewardTokenMint").and_then(serde_json::Value::as_str),
|
||||
Some("RewardMint111")
|
||||
);
|
||||
assert_eq!(
|
||||
materialized.get("rewardAmountRaw").and_then(serde_json::Value::as_str),
|
||||
Some("42")
|
||||
);
|
||||
assert_eq!(
|
||||
materialized
|
||||
.get("rewardMaterializationSource")
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("allowlisted_reward_inner_spl_transfer")
|
||||
);
|
||||
assert_eq!(
|
||||
materialized.get("eventActionability").and_then(serde_json::Value::as_str),
|
||||
Some("reward_materialized")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -196,7 +196,9 @@ WHERE de.protocol_name = 'meteora_dlmm'
|
||||
'meteora_dlmm.swap_exact_out',
|
||||
'meteora_dlmm.swap_exact_out2',
|
||||
'meteora_dlmm.swap_with_price_impact',
|
||||
'meteora_dlmm.swap_with_price_impact2'
|
||||
'meteora_dlmm.swap_with_price_impact2',
|
||||
'meteora_dlmm.swap_event',
|
||||
'meteora_dlmm.swap2_evt'
|
||||
)
|
||||
GROUP BY de.event_kind
|
||||
HAVING trade_count > 0 OR candle_count > 0
|
||||
@@ -268,7 +270,32 @@ GROUP BY de.event_kind
|
||||
HAVING fee_count > 0 OR reward_count > 0
|
||||
ORDER BY de.event_kind;
|
||||
|
||||
-- 13. Global watchlist after replay.
|
||||
-- 13. Limit/orderbook no trade/candle double-count. Target: empty.
|
||||
SELECT
|
||||
de.event_kind,
|
||||
COUNT(DISTINCT te.id) AS trade_count,
|
||||
COUNT(DISTINCT pc.id) AS candle_count,
|
||||
COUNT(DISTINCT obe.id) AS orderbook_count,
|
||||
MIN(tx.signature) AS sample_signature
|
||||
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_pair_candles pc ON pc.pair_id = te.pair_id
|
||||
LEFT JOIN k_sol_orderbook_events obe ON obe.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'meteora_dlmm'
|
||||
AND (
|
||||
de.event_kind LIKE '%limit_order%'
|
||||
OR de.event_kind IN (
|
||||
'meteora_dlmm.place_limit_order_evt',
|
||||
'meteora_dlmm.cancel_limit_order_evt',
|
||||
'meteora_dlmm.close_limit_order_evt'
|
||||
)
|
||||
)
|
||||
GROUP BY de.event_kind
|
||||
HAVING trade_count > 0 OR candle_count > 0
|
||||
ORDER BY trade_count DESC, candle_count DESC, de.event_kind;
|
||||
|
||||
-- 14. Global watchlist after replay.
|
||||
SELECT
|
||||
COALESCE(json_extract(de.payload_json, '$.upstreamDecoderCode'), de.protocol_name) AS backlog_decoder,
|
||||
de.event_kind,
|
||||
@@ -283,3 +310,63 @@ WHERE de.protocol_name IN ('upstream_git', 'meteora_dlmm')
|
||||
GROUP BY backlog_decoder, de.event_kind, upstream_entry_name, upstream_discriminator_hex
|
||||
ORDER BY decoded_count DESC, backlog_decoder, de.event_kind
|
||||
LIMIT 100;
|
||||
|
||||
-- 15. Coverage observed > materialized explained by failed transactions.
|
||||
-- The final accepted residual is close_bin_array: 16 observed / 14 materialized,
|
||||
-- with 2 failed transactions Custom 6015 and 0 business materialization on failed tx.
|
||||
SELECT
|
||||
ce.entry_name,
|
||||
ce.entry_kind,
|
||||
ce.event_family,
|
||||
ce.expected_db_target,
|
||||
ce.local_event_kind,
|
||||
ce.discriminator_hex,
|
||||
ce.observed_count,
|
||||
ce.materialized_count,
|
||||
ce.observed_count - ce.materialized_count AS missing_count
|
||||
FROM k_sol_dex_event_coverage_entries ce
|
||||
WHERE ce.decoder_code = 'meteora_dlmm'
|
||||
AND ce.observed_count > ce.materialized_count
|
||||
AND ce.observed_count > 0
|
||||
ORDER BY missing_count DESC, ce.entry_kind, ce.entry_name, ce.discriminator_hex;
|
||||
|
||||
-- 16. close_bin_array success/failed split.
|
||||
-- Final acceptable result:
|
||||
-- success rows -> decoded_count = lifecycle_count = 14
|
||||
-- failed rows -> decoded_count = 2, lifecycle_count = 0
|
||||
SELECT
|
||||
de.event_kind,
|
||||
tx.err_json,
|
||||
COUNT(*) AS decoded_count,
|
||||
COUNT(DISTINCT ple.id) AS lifecycle_count,
|
||||
MIN(tx.signature) AS sample_signature
|
||||
FROM k_sol_dex_decoded_events de
|
||||
JOIN k_sol_chain_transactions tx
|
||||
ON tx.id = de.transaction_id
|
||||
LEFT JOIN k_sol_pool_lifecycle_events ple
|
||||
ON ple.decoded_event_id = de.id
|
||||
WHERE de.protocol_name = 'meteora_dlmm'
|
||||
AND de.event_kind = 'meteora_dlmm.close_bin_array'
|
||||
GROUP BY de.event_kind, tx.err_json
|
||||
ORDER BY decoded_count DESC;
|
||||
|
||||
-- 17. Logical duplicate coverage rows. Target: empty.
|
||||
SELECT
|
||||
decoder_code,
|
||||
COALESCE(program_id, '') AS program_id,
|
||||
entry_kind,
|
||||
entry_name,
|
||||
COALESCE(discriminator_hex, '') AS discriminator_hex,
|
||||
COALESCE(local_event_kind, '') AS local_event_kind,
|
||||
COUNT(*) AS duplicate_count
|
||||
FROM k_sol_dex_event_coverage_entries
|
||||
WHERE decoder_code = 'meteora_dlmm'
|
||||
GROUP BY
|
||||
decoder_code,
|
||||
COALESCE(program_id, ''),
|
||||
entry_kind,
|
||||
entry_name,
|
||||
COALESCE(discriminator_hex, ''),
|
||||
COALESCE(local_event_kind, '')
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY duplicate_count DESC, entry_kind, entry_name, discriminator_hex;
|
||||
|
||||
Reference in New Issue
Block a user