0.7.47-1FE5
This commit is contained in:
@@ -80,3 +80,10 @@
|
||||
0.7.46-demo3 - Correction ciblée de Demo3 pour la découverte/backfill : ajout d’un décodage léger des instructions `meteora_damm_v1` connues par discriminant upstream Git dans `onchain_dex_pair_discovery`, classification instruction-scoped prioritaire pour éviter qu’un `Swap` soit classé `add_liquidity` à cause de logs mixtes de transaction, filtrage `target_event` strict sur les surfaces explicites, conservation des transactions mixtes quand un target explicite est demandé malgré `excludeSwaps`, et ajout des cibles UI `create_lock_escrow` / `lock_liquidity`.
|
||||
0.7.46-demo3-paged - Amélioration Demo3 discovery : pagination `getSignaturesForAddress` via `before_signature` / `until_signature`, scan de plusieurs adresses source dans une seule requête, déduplication des signatures multi-pool, compteur de pages, curseurs `next_before` par adresse et ordre de traitement `newest_first` / `oldest_first` pour constituer un corpus depuis les premières signatures d’un pool sans promouvoir de nouveau `program_id`.
|
||||
0.7.46-final - Renommage documentaire et payload des anciens statuts/fonctions liés au dépôt source vers une terminologie générique `upstream_git_*` : `proofStatus` utilise désormais `upstream_git_local_corpus_observed`, `upstream_git_mapped_unverified` et `upstream_git_layout_unverified`; les payloads DAMM v1 utilisent `upstreamInstructionName`; la documentation prépare `0.7.47` comme Upstream Git Registry / DEX discovery preparation au lieu d’une tranche DAMM v2 immédiate.
|
||||
|
||||
0.7.47 - Upstream Git Registry / DEX discovery preparation : ajout d’un registre générique `upstream_git` pour indexer `program_id`, discriminants d’instructions/events, noms d’entrées et familles de programmes depuis Carbon et sources Git/IDL externes ; extension Demo3 aux targets multi-surfaces, orderbook, burn/mint/transfer/wrap/unwrap/stake ; ajout de groupes de signatures réussies/échouées pour alimenter Demo2 ; maintien strict de l’invariant : aucune entrée upstream Git ne produit trade/candle sans decoder spécialisé et corpus local.
|
||||
0.7.47-openbook-v2-audit - Ajout d’un decoder local `openbook_v2` audit-only : instructions `place_order`, `cancel_order_by_client_order_id`, `consume_events`, `settle_funds`, `close_open_orders_account`; cleanup du fallback `upstream_git.instruction_match`; extraction audit des `Program return` et `Program data`; mapping des logs `FillLog`, `OpenOrdersPositionLog`, `TotalOrderFillEvent`, `SettleFundsLog`; aucune matérialisation trade/candle.
|
||||
0.7.47-phoenix-v1-audit - Ajout d’un decoder local `phoenix_v1` audit-only : `order_place`, `order_cancel`, `funds_withdraw`, `log`; parsing strict des instructions log `0x0f`; décodage audit du header Phoenix log et des events `Reduce`, `Place`, `TimeInForce`; correction du mapping `PlaceMultiplePostOnlyOrders` tag `0x10`; aucune matérialisation trade/candle.
|
||||
0.7.47-doc-matrix - Révision documentaire : ajout d’une matrice DEX dédiée, ajout explicite des sources Git/IDL à consulter, et redécoupage du plan `0.7.48+` en un DEX/version par tranche afin d’éviter les lots “tous events/tous decoders” trop larges.
|
||||
|
||||
0.7.47-doc-event-coverage - Ajout d'une matrice événementielle complémentaire `DEX_EVENT_COVERAGE_MATRIX.md` pour suivre, par DEX/version, les familles `swap`, `pool_create`, `liquidity`, `position`, `fee`, `reward`, `admin/config`, `mint`, `burn`, `transfer`, `account_create/close`, `wrap/unwrap`, `orderbook`, `vault`, `lock/unlock`, `launch` et `migration`; ajout de `DB_EVENT_MODEL_REVIEW.md` pour clarifier que `k_sol_dex_decoded_events` suffit à l'audit-only mais que des tables transversales sont nécessaires pour exploiter transfers, orderbook, vault, launch/migration et coverage upstream en requêtes métier.
|
||||
|
||||
10
Cargo.toml
10
Cargo.toml
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.7.46"
|
||||
version = "0.7.47"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||
@@ -31,16 +31,15 @@ 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.0-rc.1", features = ["zstd"] }
|
||||
solana-account-decoder-client-types = { version = "^4.0", features = ["zstd"] }
|
||||
solana-address-lookup-table-interface = { version = "^3.1", features = ["serde"] }
|
||||
solana-client = { version = ">=4.0.0-rc.0", features = [] }
|
||||
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.0-rc.0", features = [] }
|
||||
#solana-rpc-client-types = { version = "^4.0", 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.0-rc.1", features = [] }
|
||||
solana-transaction-status-client-types = { version = "^4.0", 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 = [] }
|
||||
@@ -89,3 +88,4 @@ single_match = "allow"
|
||||
manual_unwrap_or_default = "allow"
|
||||
manual_find = "allow"
|
||||
explicit_counter_loop = "allow"
|
||||
get_first = "allow"
|
||||
|
||||
291
DB_EVENT_MODEL_REVIEW.md
Normal file
291
DB_EVENT_MODEL_REVIEW.md
Normal file
@@ -0,0 +1,291 @@
|
||||
# Database Event Model Review — `khadhroony-bobobot` `0.7.47-1FE5`
|
||||
|
||||
## Conclusion courte
|
||||
|
||||
La base actuelle est **suffisante pour continuer le décodage exhaustif en audit-only**, parce que `k_sol_dex_decoded_events` garde les events décodés avec `payload_json`.
|
||||
|
||||
La base actuelle est **partiellement insuffisante pour exploiter tous les events en requêtes métier**, parce que certaines familles importantes n’ont pas encore de tables dédiées ou de modèle normalisé :
|
||||
|
||||
- transfers SPL / Token-2022 ;
|
||||
- token account create/close ;
|
||||
- wrap/unwrap SOL ;
|
||||
- orderbook orders/fills/settlements ;
|
||||
- vault deposit/withdraw ;
|
||||
- launch/migration ;
|
||||
- lock/unlock LP ;
|
||||
- staking/unstaking ;
|
||||
- coverage matrix persistée par discriminator/event.
|
||||
|
||||
## Ce qui existe déjà
|
||||
|
||||
D’après le README, le modèle contient déjà notamment :
|
||||
|
||||
- `k_sol_chain_transactions`;
|
||||
- `k_sol_chain_instructions`;
|
||||
- `k_sol_dex_decoded_events`;
|
||||
- `k_sol_trade_events`;
|
||||
- `k_sol_liquidity_events`;
|
||||
- `k_sol_pool_lifecycle_events`;
|
||||
- `k_sol_fee_events`;
|
||||
- `k_sol_reward_events`;
|
||||
- `k_sol_pool_admin_events`;
|
||||
- `k_sol_token_mint_events`;
|
||||
- `k_sol_token_burn_events`;
|
||||
- `k_sol_transaction_classifications`;
|
||||
- `k_sol_protocol_candidates`;
|
||||
- `k_sol_dex_decode_replay_ledger`.
|
||||
|
||||
Ces tables couvrent déjà les besoins principaux :
|
||||
|
||||
| Besoin | Couverture actuelle |
|
||||
|---|---|
|
||||
| Stockage brut/audit de tout event décodé | Oui, via `k_sol_dex_decoded_events.payload_json`. |
|
||||
| Trades/candles | Oui. |
|
||||
| Liquidity/lifecycle/fee/reward/admin | Oui, au moins structurellement. |
|
||||
| Mint/burn | Oui, structurellement. |
|
||||
| Replay/skip sûr | Oui, via ledger. |
|
||||
| Event coverage attendu vs observé | Non ou seulement implicite. |
|
||||
| Transfers/token account lifecycle | Non spécialisé. |
|
||||
| Orderbook events | Non spécialisé. |
|
||||
| Vault events | Non spécialisé. |
|
||||
| Launch/migration | Non spécialisé ou dispersé. |
|
||||
|
||||
## Ne pas modifier la DB trop vite
|
||||
|
||||
Il ne faut pas créer une table pour chaque DEX ou chaque event upstream.
|
||||
|
||||
La bonne stratégie :
|
||||
|
||||
1. Décoder tout ce qu’on peut en `k_sol_dex_decoded_events`.
|
||||
2. Ajouter `eventFamily`, `eventSemanticKind`, `eventActionability`, `proofStatus`, `sourceRepo`, `sourcePath`.
|
||||
3. Matérialiser seulement les familles prouvées et utiles.
|
||||
4. Ajouter des tables transversales uniquement quand plusieurs DEX en ont besoin.
|
||||
|
||||
## Ajouts DB recommandés
|
||||
|
||||
### 1. `k_sol_dex_event_coverage_entries`
|
||||
|
||||
But : stocker ce qui est **attendu/listé** depuis les sources upstream, même si non observé.
|
||||
|
||||
Colonnes conceptuelles :
|
||||
|
||||
```text
|
||||
id
|
||||
decoder_code
|
||||
program_id
|
||||
program_family
|
||||
surface_kind
|
||||
source_repo
|
||||
source_path
|
||||
entry_kind -- instruction/event/account/log/program_data
|
||||
entry_name
|
||||
discriminator_hex
|
||||
discriminator_len
|
||||
event_family -- swap/burn/mint/admin/etc.
|
||||
expected_db_target
|
||||
proof_status
|
||||
local_event_kind
|
||||
observed_count
|
||||
materialized_count
|
||||
trade_count
|
||||
first_signature
|
||||
last_signature
|
||||
notes
|
||||
created_at
|
||||
updated_at
|
||||
```
|
||||
|
||||
Rôle : rendre la couverture objectivable. Exemple : “Carbon liste 42 instructions Raydium CPMM, notre code en décode 18, 4 sont matérialisées”.
|
||||
|
||||
### 2. `k_sol_token_transfer_events`
|
||||
|
||||
But : matérialiser les transfers significatifs hors trade.
|
||||
|
||||
Colonnes conceptuelles :
|
||||
|
||||
```text
|
||||
id
|
||||
transaction_id
|
||||
instruction_id
|
||||
decoded_event_id
|
||||
signature
|
||||
slot
|
||||
program_id
|
||||
token_program_id
|
||||
mint
|
||||
source_token_account
|
||||
destination_token_account
|
||||
source_owner
|
||||
destination_owner
|
||||
amount_raw
|
||||
amount_ui
|
||||
transfer_kind -- transfer, transfer_checked, routed_transfer, vault_transfer
|
||||
reason -- audit_only, vault_movement, migration, settlement, unknown
|
||||
payload_json
|
||||
```
|
||||
|
||||
Important : ne pas créer de trade depuis cette table. Elle sert au risque/analyse.
|
||||
|
||||
### 3. `k_sol_token_account_events`
|
||||
|
||||
But : suivre create/close/init ATA/token accounts.
|
||||
|
||||
```text
|
||||
id
|
||||
transaction_id
|
||||
instruction_id
|
||||
decoded_event_id
|
||||
signature
|
||||
slot
|
||||
event_kind -- create_ata, init_account, close_account, wrap_sol, unwrap_sol
|
||||
account_address
|
||||
mint
|
||||
owner
|
||||
token_program_id
|
||||
lamports_delta
|
||||
payload_json
|
||||
```
|
||||
|
||||
Cela aide à comprendre WSOL wrap/unwrap, close accounts, cleanup bots, préparation de trades.
|
||||
|
||||
### 4. `k_sol_orderbook_events`
|
||||
|
||||
But : stocker OpenBook/Phoenix et autres CLOB sans les confondre avec swaps AMM.
|
||||
|
||||
```text
|
||||
id
|
||||
transaction_id
|
||||
instruction_id
|
||||
decoded_event_id
|
||||
signature
|
||||
slot
|
||||
protocol_name
|
||||
market_account
|
||||
event_kind -- order_place, order_cancel, order_fill, settle_funds, consume_events, open_orders_create, open_orders_close
|
||||
side
|
||||
price_lots
|
||||
base_lots
|
||||
quote_lots
|
||||
maker
|
||||
taker
|
||||
client_order_id
|
||||
raw_event_name
|
||||
interpretation_status
|
||||
payload_json
|
||||
```
|
||||
|
||||
Les fills ne deviennent `trade_events` que quand maker/taker, base/quote, lots/decimals et sens économique sont validés.
|
||||
|
||||
### 5. `k_sol_vault_events`
|
||||
|
||||
But : suivre vault deposit/withdraw, Meteora Vault, Kamino/Vault-like programs.
|
||||
|
||||
```text
|
||||
id
|
||||
transaction_id
|
||||
instruction_id
|
||||
decoded_event_id
|
||||
signature
|
||||
slot
|
||||
protocol_name
|
||||
vault_account
|
||||
event_kind -- deposit, withdraw, claim, rebalance, update_config
|
||||
mint_a
|
||||
mint_b
|
||||
amount_a_raw
|
||||
amount_b_raw
|
||||
owner
|
||||
payload_json
|
||||
```
|
||||
|
||||
### 6. `k_sol_launch_events`
|
||||
|
||||
But : séparer launch/bonding/migration du DEX effectif.
|
||||
|
||||
```text
|
||||
id
|
||||
transaction_id
|
||||
instruction_id
|
||||
decoded_event_id
|
||||
signature
|
||||
slot
|
||||
launch_protocol
|
||||
event_kind -- create, buy, sell, migrate, graduate, initialize_curve, close_curve
|
||||
token_mint
|
||||
curve_account
|
||||
migration_target_program
|
||||
migration_pool
|
||||
quote_mint
|
||||
amount_token_raw
|
||||
amount_quote_raw
|
||||
payload_json
|
||||
```
|
||||
|
||||
### 7. `k_sol_liquidity_lock_events`
|
||||
|
||||
But : traiter LP lock/unlock explicitement.
|
||||
|
||||
```text
|
||||
id
|
||||
transaction_id
|
||||
instruction_id
|
||||
decoded_event_id
|
||||
signature
|
||||
slot
|
||||
protocol_name
|
||||
pool_id
|
||||
pair_id
|
||||
lock_account
|
||||
owner
|
||||
event_kind -- create_lock, lock, unlock, extend_lock, close_lock
|
||||
lp_mint
|
||||
lp_amount_raw
|
||||
unlock_time
|
||||
payload_json
|
||||
```
|
||||
|
||||
## Alternative minimaliste
|
||||
|
||||
Si on veut éviter trop de migrations immédiates, le minimum à ajouter d’abord est :
|
||||
|
||||
1. `k_sol_dex_event_coverage_entries`;
|
||||
2. `k_sol_token_transfer_events`;
|
||||
3. `k_sol_orderbook_events`.
|
||||
|
||||
Les autres tables peuvent attendre.
|
||||
|
||||
## Impact sur le plan des versions
|
||||
|
||||
Chaque version DEX doit répondre à deux questions :
|
||||
|
||||
### Couverture decoder
|
||||
|
||||
- A-t-on listé tous les events upstream ?
|
||||
- A-t-on un decoder audit pour chaque discriminator connu ?
|
||||
- Les events non observés sont-ils marqués `upstream_git_mapped_unverified` ?
|
||||
|
||||
### Couverture DB
|
||||
|
||||
- L’event peut-il rester dans `k_sol_dex_decoded_events` ?
|
||||
- Doit-il être matérialisé dans une table existante ?
|
||||
- Faut-il une table transversale nouvelle ?
|
||||
- Une table nouvelle peut-elle servir à plusieurs DEX ?
|
||||
|
||||
## Décision pratique pour `0.7.48`
|
||||
|
||||
Avant de reprendre `raydium_cpmm`, faire une micro-tranche DB/doc :
|
||||
|
||||
```text
|
||||
0.7.48-pre — event coverage + DB model checkpoint
|
||||
```
|
||||
|
||||
Objectif :
|
||||
|
||||
- ajouter ou documenter `k_sol_dex_event_coverage_entries`;
|
||||
- ne pas encore ajouter toutes les tables métier ;
|
||||
- produire un rapport par DEX :
|
||||
- listed events,
|
||||
- decoded events,
|
||||
- materialized events,
|
||||
- missing DB target,
|
||||
- trade_count invariant.
|
||||
204
DEX_DECODER_MATRIX.md
Normal file
204
DEX_DECODER_MATRIX.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# DEX Decoder Matrix — `khadhroony-bobobot` `0.7.47-1FE5`
|
||||
|
||||
Cette matrice complète `kb_lib/src/dex_support_matrix.rs`. Elle documente **ce qui est fait**, **ce qui reste à faire**, et **le niveau de preuve attendu** par DEX/version.
|
||||
|
||||
## Règle de lecture
|
||||
|
||||
| Statut | Sens |
|
||||
|---|---|
|
||||
| `supported` | Decoder local actif et matérialisation métier possible sur corpus validé. |
|
||||
| `partial` | Decoder partiel ou surface partielle : des events existent, mais la couverture n’est pas complète. |
|
||||
| `audit-only` | Decoder local spécialisé, mais aucun trade/candle/matérialisation marché. |
|
||||
| `planned` | Program id ou surface connue, mais decoder non prioritaire ou non activé. |
|
||||
| `to_verify` | Source externe ou candidat : aucun statut vérifié sans corpus local. |
|
||||
| `ignored/historical` | À conserver pour historique ou compatibilité, mais non prioritaire. |
|
||||
|
||||
## Sources upstream à comparer
|
||||
|
||||
- Carbon decoders : `https://github.com/sevenlabs-hq/carbon/tree/main/decoders`
|
||||
- Solana Streamer : `https://github.com/0xfnzero/solana-streamer`
|
||||
- Sol Parser SDK IDLs : `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl`
|
||||
- Pinax Substreams Solana IDLs : `https://github.com/pinax-network/substreams-solana-idls/tree/main/src`
|
||||
- HODL Warden Solana Tx Parser : `https://github.com/hodlwarden/solana-tx-parser/tree/main/src`
|
||||
- OpenBook v2 : `https://github.com/openbook-dex/openbook-v2`
|
||||
- Phoenix on-chain MM : `https://github.com/all-in-one-blockchain/phoenix-onchain-mm`
|
||||
- Vybe DEX/AMM support list : `https://docs.vybenetwork.com/docs/available-dexs-amms`
|
||||
|
||||
## Matrice prioritaire DEX/version
|
||||
|
||||
| Ordre | DEX/version | État actuel | Fait | Reste à faire |
|
||||
|---:|---|---|---|---|
|
||||
| 1 | `raydium_cpmm` | `supported` | Swaps matérialisés ; premiers non-swaps prouvés (`initialize`, `withdraw`, `collect_creator_fee`) ; trades/candles OK. | Comparer tous les discriminants Carbon/IDL ; compléter fees/admin/lifecycle ; rejouer sur base dédiée ; vérifier absence d’audits orphelins. |
|
||||
| 2 | `raydium_clmm` | `supported` | Swaps `swap`/`swap_v2` ; events positions/liquidité prouvés ; matérialisation non-trade existante. | Repasser tous les events Carbon/IDL : open/close position, rewards, protocol fees, Token-2022 ; compléter audit → materialized si corpus. |
|
||||
| 3 | `pump_swap` | `supported` | `buy`/`sell` décodés et matérialisés ; trade/candle OK. | Ajouter tous les events Carbon/Solana Streamer : cashback, fee, volume accumulator, admin/config ; conserver les non-trades hors candles. |
|
||||
| 4 | `pump_fun` | `partial / launch_surface` | Création/token launch partiellement décodée ; intégrée au pipeline de listings. | Traiter tous les events Pump.fun disponibles : buy/sell/migrate/create/update ; séparer bonding/launch de DEX effectif ; valider migration vers PumpSwap. |
|
||||
| 5 | `meteora_dbc` | `partial` | Swaps/instruction audits observés ; Demo3 donne du corpus. | Couverture complète DBC : launch/bonding curve, swap, migration, config/admin, fees ; matérialiser seulement ce qui est prouvé. |
|
||||
| 6 | `meteora_dlmm` | `supported` | Couverture avancée validée en `0.7.45` : swaps, liquidity, positions, lifecycle, fees ; non-trade matérialisé. | Résoudre les audits résiduels non mappés ; comparer Carbon/IDL pour events rewards/admin restants ; revalidation base neuve. |
|
||||
| 7 | `meteora_damm_v1` | `supported / partial events` | 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. |
|
||||
| 8 | `meteora_damm_v2` | `partial` | `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. |
|
||||
| 9 | `phoenix_v1` | `audit-only` | 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. |
|
||||
| 10 | `openbook_v2` | `audit-only` | Decoder local audit-only ; instructions order/cancel/consume/settle ; `Program data` mappé : `FillLog`, `OpenOrdersPositionLog`, `TotalOrderFillEvent`, `SettleFundsLog`; `trade_count=0`. | Vérifier layouts fill/out et sens maker/taker/base/quote ; ajouter table audit éventuelle ; ne matérialiser trades qu’après validation du sens économique. |
|
||||
| 11 | `orca_whirlpools` | `partial` | Premier decoder historique présent ; swaps/create_pool partiels. | Comparer Carbon/IDL complet ; couvrir liquidity, positions, fees/rewards, tick arrays ; valider swaps exploitables et non-trades. |
|
||||
| 12 | `raydium_launchlab` | `planned launch` | Entrée canonique locale LaunchLab/Launchpad ; program id connu localement. | Décoder launch/migration ; ne pas confondre avec CPMM/CLMM/AMM v4 ; rattacher aux pools tradables. |
|
||||
| 13 | `meteora_vault` | `to_verify` | Présent comme indice upstream / compte associé. | Corpus direct obligatoire ; decoder séparé si events vault réels ; aucune promotion via DAMM indirect. |
|
||||
| 14 | `fluxbeam` | `partial/to_verify` | Decoder initial existant ; Demo3 peut produire des candidats. | Vérifier source/IDL ; compléter swap, pool, liquidity, fees/admin ; matérialisation uniquement après corpus. |
|
||||
| 15 | `dexlab` | `partial/to_verify` | Decoder initial historique ; ancienne entrée beta supprimée. | Reconfirmer program id/source ; décoder events disponibles ; distinguer DexLab natif et liens OpenBook/market. |
|
||||
| 16 | `lifinity_amm_v2` | `to_verify` | Program id listé par sources externes/Vybe ; pas de corpus concluant. | Trouver IDL/source ; Demo3 par program/market ; audit-only d’abord. |
|
||||
| 17 | `stabble_stable_swap` / `stabble_weighted_swap` | `to_verify` | Program ids/indices via sources externes ; candidats Demo3 observables. | Source/IDL + corpus + decoder audit-only ; déterminer surface AMM et montants exploitables. |
|
||||
| 18 | `bonkswap` | `to_verify` | Program id/Carbon/Vybe selon registre ; swaps candidats possibles. | Vérifier program id, source et corpus ; décoder tous events ; pas de trade sans montants. |
|
||||
| 19 | `boop` / `boop_fun` | `to_verify / launch` | Entrée de découverte. | Séparer launch surface et swap effectif ; corpus + source obligatoire. |
|
||||
| 20 | `moonshot` / `moonit` | `to_verify / launch` | Moonshot buy/sell observés via upstream candidates ; Moonit launch attribution historique. | Source/IDL + migration + rattachement pools ; éviter heuristiques seules. |
|
||||
| 21 | `heaven` | `to_verify` | Program id/candidat ajouté en matrice. | Vérifier s’il est launch, AMM ou les deux ; corpus dédié. |
|
||||
| 22 | `printr` | `to_verify` | Preset Demo3 ajouté ; candidats observables. | Source/IDL, discriminants, corpus, decoder audit-only. |
|
||||
| 23 | `metadao_*` | `to_verify` | Presets spécifiques : launchpad, bid wall, futarchy, AMM. | Traiter par programme séparé ; ne pas utiliser mint ids comme program ids ; corpus obligatoire. |
|
||||
| 24 | `raydium_stable_swap` | `planned/historical` | Entrée conservée. | Reprendre uniquement si corpus réel ; stable AMM séparé de CPMM/CLMM. |
|
||||
| 25 | `jupiter_*`, `dflow_aggregator_v4`, `okx_dex` | `aggregator_router` | Registry/discovery pour contexte transactionnel. | Ne pas matérialiser en DEX direct ; utiliser pour routeSource/routing/context. |
|
||||
|
||||
## Checklist obligatoire par DEX/version
|
||||
|
||||
Pour chaque DEX ou version, la tranche doit fermer les points suivants :
|
||||
|
||||
- [ ] Source Git/IDL recensée.
|
||||
- [ ] Tous les `program_id` vérifiés localement ou marqués `to_verify`.
|
||||
- [ ] Tous les discriminants d’instructions listés.
|
||||
- [ ] Tous les discriminants d’events/logs listés.
|
||||
- [ ] Demo3 corpus constitué.
|
||||
- [ ] Demo2 backfill de signatures réussies.
|
||||
- [ ] Replay forcé sur base `0.7.47+`.
|
||||
- [ ] SQL : decoded events par kind.
|
||||
- [ ] SQL : `trade_count=0` pour audit-only.
|
||||
- [ ] SQL : trade/candle uniquement si montants exploitables.
|
||||
- [ ] Cleanup `upstream_git.instruction_match` si decoder spécialisé local.
|
||||
- [ ] Décision finale : `audit-only`, `materialized`, `partial`, ou `to_verify`.
|
||||
|
||||
## Notes de matérialisation
|
||||
|
||||
Un event peut devenir `materialized` uniquement si :
|
||||
|
||||
1. la transaction est `OK` ;
|
||||
2. les comptes nécessaires sont identifiés ;
|
||||
3. les mints sont fiables ;
|
||||
4. les montants sont fiables ;
|
||||
5. le sens base/quote est validé ;
|
||||
6. les requêtes SQL prouvent l’absence de faux trades/candles ;
|
||||
7. les tests et clippy sont verts.
|
||||
|
||||
|
||||
## Annexe — snapshot de `kb_lib/src/dex_support_matrix.rs` (`1FE5`)
|
||||
|
||||
| Code | Rôle | Surface | Program id status | Observed | Decoded | Materialized | Status | Skip reason |
|
||||
|---|---|---|---|---:|---:|---:|---|---|
|
||||
| `pump_fun` | `launch_surface` | `launch` | `known` | non | oui | oui | `partial` | launch_surface_requires_migration_linking_before_live_trading |
|
||||
| `pump_swap` | `dex_effective` | `AMM` | `known` | oui | oui | oui | `supported` | |
|
||||
| `raydium_cpmm` | `dex_effective` | `AMM` | `known` | oui | oui | oui | `supported` | |
|
||||
| `raydium_clmm` | `dex_effective` | `CLMM` | `known` | oui | oui | oui | `supported` | |
|
||||
| `raydium_amm_v4` | `dex_effective` | `AMM` | `known` | oui | oui | oui | `supported` | |
|
||||
| `raydium_launchlab` | `launch_surface` | `launch` | `known` | non | non | non | `planned` | decoder_and_materialization_not_enabled |
|
||||
| `raydium_liquidity_locking` | `to_verify` | `liquidity_locking` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `raydium_router` | `aggregator_router` | `router` | `known` | non | non | non | `partial` | router_not_materialized_as_direct_trade_surface |
|
||||
| `raydium_stable_swap` | `dex_effective` | `AMM` | `known` | non | non | non | `planned` | deprecated_program_not_prioritized |
|
||||
| `meteora_dlmm` | `dex_effective` | `DLMM` | `known` | oui | oui | oui | `supported` | |
|
||||
| `meteora_dlc` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | surface_and_program_id_to_verify |
|
||||
| `meteora_damm_v1` | `dex_effective` | `AMM` | `known` | oui | oui | non | `partial` | meteora_damm_v1_swap_without_amount_payload |
|
||||
| `meteora_damm_v2` | `dex_effective` | `AMM` | `known` | non | oui | oui | `partial` | not_observed_in_0_7_28_replay |
|
||||
| `meteora_dbc` | `dex_effective` | `bonding_curve` | `known` | non | oui | oui | `partial` | not_observed_in_0_7_28_replay |
|
||||
| `orca_whirlpools` | `dex_effective` | `CLMM` | `known` | non | oui | oui | `partial` | not_observed_in_0_7_28_replay |
|
||||
| `fluxbeam` | `dex_effective` | `AMM` | `known` | non | oui | oui | `partial` | not_observed_in_0_7_28_replay |
|
||||
| `dexlab` | `dex_effective` | `AMM` | `known` | non | oui | oui | `partial` | not_observed_in_0_7_28_replay |
|
||||
| `bags` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `letsbonk` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `bonk` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `bonk_fun` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `okx_dex` | `aggregator_router` | `aggregator` | `to_verify` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `boop_fun` | `launch_surface` | `launch` | `to_verify` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `moonshot` | `launch_surface` | `launch` | `to_verify` | non | non | non | `planned` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `believe` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `metadao` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | umbrella_surface_programs_split_into_specific_discovery_targets |
|
||||
| `metadao_launchpad_v0_7_0` | `to_verify` | `launch` | `to_verify` | non | non | non | `to_verify` | official_metadao_program_id_requires_local_corpus_verification |
|
||||
| `metadao_bid_wall_v0_7_0` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | official_metadao_program_id_requires_local_corpus_verification |
|
||||
| `metadao_futarchy_v0_6_0` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | official_metadao_program_id_requires_local_corpus_verification |
|
||||
| `metadao_amm_v0_5_0` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | official_metadao_program_id_requires_local_corpus_verification |
|
||||
| `printr` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | solscan_program_label_requires_local_corpus_verification |
|
||||
| `zora` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | solscan_program_label_requires_local_corpus_verification |
|
||||
| `moonit` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `launchbeam` | `launch_surface` | `launch` | `unknown` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `heaven` | `launch_surface` | `launch` | `to_verify` | non | non | non | `planned` | program_id_to_verify |
|
||||
| `gavel` | `to_verify` | `auction` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `pump_fees` | `to_verify` | `fee_program` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `meteora_pools` | `dex_effective` | `AMM` | `alias_of_meteora_damm_v1` | non | non | non | `to_verify` | program_id_alias_held_by_meteora_damm_v1 |
|
||||
| `dflow_aggregator_v4` | `aggregator_router` | `aggregator` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `drift_v2` | `to_verify` | `perps` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `jupiter_swap` | `aggregator_router` | `aggregator` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `jupiter_dca` | `aggregator_router` | `dca` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `jupiter_limit_order` | `aggregator_router` | `limit_order` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `jupiter_limit_order_2` | `aggregator_router` | `limit_order` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `jupiter_perpetuals` | `to_verify` | `perps` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `jupiter_lend` | `to_verify` | `lending` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `kamino_lending` | `to_verify` | `lending` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `kamino_vault` | `to_verify` | `vault` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `kamino_farms` | `to_verify` | `farms` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `kamino_limit_order` | `to_verify` | `limit_order` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `marginfi_v2` | `to_verify` | `lending` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `onchain_labs_dex_v1` | `dex_effective` | `AMM` | `alias_of_okx_dex` | non | non | non | `to_verify` | program_id_alias_held_by_okx_dex |
|
||||
| `onchain_labs_dex_v2` | `dex_effective` | `AMM` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `pancake_swap` | `dex_effective` | `AMM` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `vertigo` | `dex_effective` | `AMM` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `virtuals` | `launch_surface` | `launch` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `wavebreak` | `dex_effective` | `AMM` | `to_verify` | non | non | non | `to_verify` | upstream_git_program_id_requires_local_corpus_verification |
|
||||
| `aldrin` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `aldrin_v2` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `crema` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `cropper` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `lifinity_v1` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `lifinity_v2` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `mercurial` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `orca_v1` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `orca_v2` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `phoenix` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `saber` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `saber_decimals` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `openbook_v2` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `fox` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `sanctum_infinity` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `saros` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `stabble_stable_swap` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `stabble_weighted_swap` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `stepn` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `solayer` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `penguin` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `sanctum` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `one_dex` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `solfi` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `bonkswap` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `guacswap` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `invariant` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `oasis` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `token_swap` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `helium_network` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `marinade_liquid_staking` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `francium_yield_pools` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `marinade_governance` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `serum_dao` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `port_finance` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `solend_classic` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `hyperspace_nft_amm` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `magic_eden_nft_amm` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `raydium_staking_early` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `orca_aquafarm_v1` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `quarry_merge_mining` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | historical_entities_py_program_id_requires_corpus_verification |
|
||||
| `goosefx_v1` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `obric_v2` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `ondo_global_market` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `scorch` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `zerofi` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `manifest_clob` | `to_verify` | `orderbook` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `alphaq` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `goonfi` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `goonfi_v2` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `byreal` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `bisonfi` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `fusionamm` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `woofi` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `aquifer` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `humidifi` | `to_verify` | `unknown` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
| `solfi_v2` | `to_verify` | `AMM` | `to_verify` | non | non | non | `to_verify` | vybe_supported_dex_amm_requires_local_corpus_and_decoder_source |
|
||||
232
DEX_EVENT_COVERAGE_MATRIX.md
Normal file
232
DEX_EVENT_COVERAGE_MATRIX.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# DEX Event Coverage Matrix — `khadhroony-bobobot` `0.7.47-1FE5`
|
||||
|
||||
Cette matrice complète `DEX_DECODER_MATRIX.md`.
|
||||
|
||||
La matrice précédente répondait à la question : **quel DEX/version est couvert ?**
|
||||
|
||||
Cette matrice répond à la question : **quels events/instructions doivent être décodés, audit-only ou matérialisés ?**
|
||||
|
||||
## Principe
|
||||
|
||||
L’objectif n’est plus seulement de décoder les swaps. L’objectif est de décoder le maximum d’événements disponibles dans les sources Git/IDL et dans le corpus local, parce que certains événements non-trade peuvent influencer une décision de trading :
|
||||
|
||||
- perte ou ajout de liquidité ;
|
||||
- burn de tokens ou de LP ;
|
||||
- mint anormal ;
|
||||
- lock/unlock de liquidité ;
|
||||
- close account / fermeture de position ;
|
||||
- admin/config changes ;
|
||||
- fees/rewards ;
|
||||
- migration launch → DEX ;
|
||||
- market/orderbook activity ;
|
||||
- vault deposit/withdraw ;
|
||||
- changement de market cap ou de supply dérivée.
|
||||
|
||||
Un event peut donc être important même s’il ne produit jamais de `trade_event` ou de candle.
|
||||
|
||||
## Règle de couverture
|
||||
|
||||
Pour chaque DEX/version, on doit viser trois niveaux :
|
||||
|
||||
| Niveau | Description |
|
||||
|---|---|
|
||||
| `listed` | L’event/instruction existe dans une source Git/IDL/Carbon/Vybe/autre. |
|
||||
| `decoded_audit` | Le code local reconnaît l’event et le persiste dans `k_sol_dex_decoded_events` avec payload structuré ou audit-only. |
|
||||
| `materialized` | L’event alimente une table métier spécialisée : trade, liquidity, lifecycle, fee, reward, admin, mint, burn, orderbook, vault, launch/migration, etc. |
|
||||
|
||||
Ne pas sauter directement de `listed` à `materialized`.
|
||||
|
||||
## Univers minimal d’events à suivre
|
||||
|
||||
Cette liste doit devenir la grille commune pour toutes les tranches `0.7.48+`.
|
||||
|
||||
| Famille | Exemples | Impact possible | Table actuelle / cible |
|
||||
|---|---|---|---|
|
||||
| `swap/trade` | swap, buy, sell, route swap, exact in/out | Prix, volume, candles | `k_sol_trade_events`, `k_sol_pair_metrics`, `k_sol_pair_candles` |
|
||||
| `pool_create` | initialize, create_pool, initialize_market | Découverte pool/pair | `k_sol_pool_lifecycle_events`, `k_sol_pools`, `k_sol_pairs` |
|
||||
| `liquidity_add` | add_liquidity, deposit liquidity, bootstrap | Profondeur, risque, market cap indirect | `k_sol_liquidity_events` |
|
||||
| `liquidity_remove` | remove_liquidity, withdraw liquidity | Rug/liquidity drain | `k_sol_liquidity_events` |
|
||||
| `position_open` | open_position, init_position | CLMM/DLMM state | `k_sol_pool_lifecycle_events` ou future `k_sol_position_events` |
|
||||
| `position_close` | close_position, close_position_if_empty | Sortie de LP, risque | `k_sol_pool_lifecycle_events` ou future `k_sol_position_events` |
|
||||
| `fee` | claim_fee, collect_protocol_fee, collect_creator_fee | Rentabilité, activité pool | `k_sol_fee_events` |
|
||||
| `reward` | claim_reward, fund_reward, update_reward | Incitations, farming | `k_sol_reward_events` |
|
||||
| `admin/config` | set_config, update_fee, pause, whitelist, authority change | Risque protocole/pool | `k_sol_pool_admin_events` |
|
||||
| `mint` | token mint, LP mint, position NFT mint | Supply, launch, LP | `k_sol_token_mint_events` + future token activity |
|
||||
| `burn` | token burn, LP burn, position NFT burn | Supply, LP burn, risque/réassurance | `k_sol_token_burn_events` + future token activity |
|
||||
| `transfer` | SPL transfer, Token-2022 transfer, routed transfer | Flux wallet/vault, whale movement | future `k_sol_token_transfer_events` |
|
||||
| `account_create` | ATA create, token account init | Préparation trade/wallet/vault | future `k_sol_token_account_events` |
|
||||
| `account_close` | close token account, close open orders | Sortie position/wallet cleanup | future `k_sol_token_account_events` ou `k_sol_orderbook_events` |
|
||||
| `wrap/unwrap` | wrap SOL, unwrap SOL, close WSOL ATA | Routing, PnL, trade prep | future token account/activity |
|
||||
| `order_place` | place_order, post_only, IOC | Orderbook pressure | future `k_sol_orderbook_events` |
|
||||
| `order_cancel` | cancel_order, cancel_all, reduce order | Changement intention | future `k_sol_orderbook_events` |
|
||||
| `order_fill` | FillLog, fill event, trade event | Trade réel orderbook | future `k_sol_orderbook_events`; trade seulement après validation économique |
|
||||
| `settle_funds` | settle_funds, withdraw funds | Finalisation CLOB | future `k_sol_orderbook_events` |
|
||||
| `consume_events` | crank/event queue processing | Orderbook fill/out | future `k_sol_orderbook_events` |
|
||||
| `vault_deposit` | deposit into vault | TVL/risque | future `k_sol_vault_events` |
|
||||
| `vault_withdraw` | withdraw from vault | TVL drain | future `k_sol_vault_events` |
|
||||
| `lock` | lock_liquidity, create_lock_escrow | LP lock/risk | `k_sol_pool_lifecycle_events` ou future lock table |
|
||||
| `unlock` | unlock, release escrow | Risque de retrait LP | future lock/lifecycle |
|
||||
| `launch` | create bonding curve, launch pool | Origine token | future `k_sol_launch_events` |
|
||||
| `migration` | migrate to DEX, migrate liquidity | Passage launch → tradable | future `k_sol_launch_events`, pool origins |
|
||||
| `stake/unstake` | stake LP/token, unstake | Incentives/withdraw risk | future staking/reward events |
|
||||
| `oracle/price` | oracle update, price account update | Pricing/risk | future oracle/context events |
|
||||
| `unknown` | unmapped discriminator | Dette de décodage | `k_sol_dex_decoded_events` audit-only |
|
||||
|
||||
## Matrice de couverture par DEX/version
|
||||
|
||||
Légende :
|
||||
|
||||
- `M` = matérialisé déjà ou historiquement validé ;
|
||||
- `A` = audit-only local ;
|
||||
- `P` = partiel / doit être complété ;
|
||||
- `L` = listé upstream, non validé localement ;
|
||||
- `-` = non applicable connu ;
|
||||
- `?` = à vérifier.
|
||||
|
||||
| DEX/version | swap | pool create | liq add/remove | position | fee/reward | admin/config | mint/burn | transfer/account | orderbook | vault | launch/migration | état immédiat |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|
|
||||
| `raydium_cpmm` | M | P | P | - | P | P | ? | ? | - | - | ? | Reprendre en `0.7.48`, comparer tous events Carbon/IDL/fnzero. |
|
||||
| `raydium_clmm` | M | P | M/P | M/P | P | P | P | ? | - | - | ? | Reprendre en `0.7.49`, compléter positions/rewards/fees/admin. |
|
||||
| `pump_swap` | M | P | P | - | P | P | ? | P | - | - | P | Reprendre en `0.7.50`, couvrir buy/sell/cashback/fee/volume/admin. |
|
||||
| `pump_fun` | P | P | - | - | ? | P | P | P | - | - | M/P | Reprendre en `0.7.51`, launch/bonding/migration/buy/sell/create/update. |
|
||||
| `meteora_dbc` | P | P | P | - | P | P | P | ? | - | P | M/P | Reprendre en `0.7.52`, séparer bonding, swap, migration, config, fees. |
|
||||
| `meteora_dlmm` | M | M | M | M | M/P | P | ? | ? | - | ? | ? | Reprendre en `0.7.53` pour exhaustive upstream + audits résiduels. |
|
||||
| `meteora_damm_v1` | M/P | M | M/P | - | M/P | P | ? | ? | - | P | ? | Reprendre en `0.7.54`, vérifier toutes surfaces upstream non observées. |
|
||||
| `meteora_damm_v2` | P | P | L/P | - | L/P | L/P | ? | ? | - | P | ? | Reprendre en `0.7.55`, decoder tous events Carbon/source. |
|
||||
| `phoenix_v1` | A | A/P | - | - | A/P | A/P | - | A/P | A | - | - | Continuer audit des events Git, pas de trade/candle. |
|
||||
| `openbook_v2` | A | A/P | - | - | A/P | A/P | - | A/P | A | - | - | Audit-only avancé, matérialisation orderbook future. |
|
||||
| `orca_whirlpools` | P | P | L/P | L/P | L/P | L/P | P | ? | - | - | ? | Reprendre en `0.7.58`, IDL complet + corpus dédié. |
|
||||
| `raydium_launchlab` | - | P | ? | - | ? | P | P | P | - | - | P | Launch/migration après DEX effectifs. |
|
||||
| `bonkswap` | L | L | L | - | L | L | ? | ? | - | - | L | Vérifier source/corpus. |
|
||||
| `moonshot` | L/P | P | ? | - | ? | P | P | P | - | - | P | Séparer launch, buy/sell, migration. |
|
||||
| `heaven` | L/P | L/P | L/P | - | L/P | L/P | P | P | - | ? | P | Vérifier AMM vs launch. |
|
||||
| `goosefx_v1` | L/P | L/P | L/P | ? | ? | ? | ? | ? | ? | ? | ? | Vybe/Demo3 candidates ; source nécessaire. |
|
||||
| `obric_v2` | L/P | L/P | ? | ? | ? | ? | ? | ? | ? | ? | ? | Bon candidat après sources. |
|
||||
| `solfi_v2` | L/P | L/P | ? | ? | ? | ? | ? | ? | ? | ? | ? | Bon candidat après sources. |
|
||||
|
||||
## Points critiques manquants dans l’ancienne matrice
|
||||
|
||||
### `burn`
|
||||
|
||||
`burn` doit être une famille de première classe, pas seulement une sous-note. Il peut signaler :
|
||||
|
||||
- burn de LP tokens ;
|
||||
- burn de supply token ;
|
||||
- fermeture ou destruction indirecte de position ;
|
||||
- réduction du risque de dump si le burn est réel et vérifié ;
|
||||
- au contraire, faux signal si le burn ne concerne pas la bonne mint ou si le compte propriétaire est ambigu.
|
||||
|
||||
Action : ajouter `burn` à toutes les checklists DEX et aux diagnostics de couverture.
|
||||
|
||||
### `transfer`
|
||||
|
||||
Les transfers ne sont pas des trades par défaut, mais ils sont nécessaires pour :
|
||||
|
||||
- repérer vault movements ;
|
||||
- détecter migration / liquidity routing ;
|
||||
- comprendre des orderbook settle/fill ;
|
||||
- analyser whale movement ou sortie de pool.
|
||||
|
||||
Action : prévoir une table dédiée plutôt que tout stocker uniquement dans `payload_json`.
|
||||
|
||||
### `account close/create`
|
||||
|
||||
Les close/create ATA sont utiles pour détecter :
|
||||
|
||||
- fin de route WSOL ;
|
||||
- sortie de position ;
|
||||
- cleanup après swap ;
|
||||
- close open-orders account ;
|
||||
- activité de bots.
|
||||
|
||||
Action : famille dédiée `token_account` / `account_lifecycle`.
|
||||
|
||||
## Checklist exhaustive par DEX
|
||||
|
||||
Pour chaque DEX/version, la tranche doit remplir un tableau événementiel :
|
||||
|
||||
| Colonne | Description |
|
||||
|---|---|
|
||||
| `source_repo` | Git/IDL/source utilisée. |
|
||||
| `source_path` | Chemin exact du fichier source. |
|
||||
| `decoder_code` | Code interne/upstream. |
|
||||
| `program_id` | Program id ou `to_verify`. |
|
||||
| `entry_kind` | `instruction`, `event`, `account`, `log`, `program_data`. |
|
||||
| `entry_name` | Nom source exact. |
|
||||
| `discriminator_hex` | Discriminator ou tag. |
|
||||
| `discriminator_len` | Longueur en octets. |
|
||||
| `event_family` | Famille commune : swap, burn, admin, order_fill, etc. |
|
||||
| `local_event_kind` | Event local produit. |
|
||||
| `local_status` | `not_implemented`, `audit_only`, `decoded`, `materialized`. |
|
||||
| `db_target` | Table cible ou `k_sol_dex_decoded_events_only`. |
|
||||
| `proof_status` | Statut upstream/local. |
|
||||
| `observed_count` | Count local après replay. |
|
||||
| `materialized_count` | Count table métier. |
|
||||
| `trade_count` | Count trades générés, doit être 0 sauf swap validé. |
|
||||
| `notes` | Ambiguïtés, layout, corpus, reste à faire. |
|
||||
|
||||
## Requêtes SQL génériques de couverture
|
||||
|
||||
### Couverture decoded events par programme
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
protocol_name,
|
||||
event_kind,
|
||||
program_id,
|
||||
json_extract(payload_json, '$.upstreamEntryName') AS upstream_entry_name,
|
||||
json_extract(payload_json, '$.upstreamDiscriminatorHex') AS upstream_discriminator_hex,
|
||||
COUNT(*) AS n
|
||||
FROM k_sol_dex_decoded_events
|
||||
GROUP BY
|
||||
protocol_name,
|
||||
event_kind,
|
||||
program_id,
|
||||
upstream_entry_name,
|
||||
upstream_discriminator_hex
|
||||
ORDER BY protocol_name, n DESC;
|
||||
```
|
||||
|
||||
### Sécurité trades pour audit-only
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
de.protocol_name,
|
||||
de.event_kind,
|
||||
COUNT(te.id) AS trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.event_kind LIKE '%_audit'
|
||||
OR de.protocol_name IN ('upstream_git', 'phoenix_v1', 'openbook_v2')
|
||||
GROUP BY de.protocol_name, de.event_kind
|
||||
ORDER BY trade_count DESC;
|
||||
```
|
||||
|
||||
### Vérifier burn/mint présents dans decoded payloads
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
protocol_name,
|
||||
event_kind,
|
||||
json_extract(payload_json, '$.eventLifecycleKind') AS lifecycle,
|
||||
json_extract(payload_json, '$.eventActionability') AS actionability,
|
||||
COUNT(*) AS n
|
||||
FROM k_sol_dex_decoded_events
|
||||
WHERE event_kind LIKE '%burn%'
|
||||
OR event_kind LIKE '%mint%'
|
||||
OR lifecycle IN ('burn', 'mint')
|
||||
GROUP BY protocol_name, event_kind, lifecycle, actionability
|
||||
ORDER BY n DESC;
|
||||
```
|
||||
|
||||
## Décision
|
||||
|
||||
À partir de maintenant, une tranche DEX n’est pas complète si elle ne liste que les swaps. Elle doit explicitement indiquer :
|
||||
|
||||
- events source listés ;
|
||||
- events décodés audit-only ;
|
||||
- events matérialisés ;
|
||||
- events volontairement non implémentés ;
|
||||
- events non observés localement ;
|
||||
- trous de DB éventuels.
|
||||
191
NEXT_SESSION_PROMPT_0.7.47_1FE5_CONTINUATION_V2.md
Normal file
191
NEXT_SESSION_PROMPT_0.7.47_1FE5_CONTINUATION_V2.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Prompt de reprise — khadhroony-bobobot `0.7.47-1FE5`
|
||||
|
||||
Reprise du projet `khadhroony-bobobot`.
|
||||
|
||||
## Archive de départ
|
||||
|
||||
Utiliser comme base de travail :
|
||||
|
||||
```text
|
||||
kb_lib-v0.7.47-1FE5-full.zip
|
||||
```
|
||||
|
||||
Joindre aussi les docs mises à jour :
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
DEX_DECODER_MATRIX.md
|
||||
```
|
||||
|
||||
## Décision de planification
|
||||
|
||||
Ne plus tenter “tous les events de tous les decoders” dans une seule session. L’objectif reste de couvrir tous les decoders disponibles dans Carbon et les sources Git/IDL, mais par tranches DEX/version.
|
||||
|
||||
Ordre cible :
|
||||
|
||||
```text
|
||||
raydium_cpmm
|
||||
raydium_clmm
|
||||
pump_swap
|
||||
pump_fun
|
||||
meteora_dbc
|
||||
meteora_dlmm
|
||||
meteora_damm_v1
|
||||
meteora_damm_v2
|
||||
phoenix_v1
|
||||
openbook_v2
|
||||
orca_whirlpools
|
||||
launch surfaces
|
||||
DEX historiques / candidats
|
||||
```
|
||||
|
||||
## Sources upstream obligatoires
|
||||
|
||||
Ces sources sont des indices de décodage, pas des preuves de validation locale :
|
||||
|
||||
```text
|
||||
https://github.com/sevenlabs-hq/carbon/tree/main/decoders
|
||||
https://github.com/0xfnzero/solana-streamer
|
||||
https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl
|
||||
https://github.com/pinax-network/substreams-solana-idls/tree/main/src
|
||||
https://github.com/hodlwarden/solana-tx-parser/tree/main/src
|
||||
https://github.com/openbook-dex/openbook-v2
|
||||
https://github.com/all-in-one-blockchain/phoenix-onchain-mm
|
||||
https://docs.vybenetwork.com/docs/available-dexs-amms
|
||||
```
|
||||
|
||||
## État validé
|
||||
|
||||
Dernier état validé côté `kb_lib` :
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib
|
||||
371 passed
|
||||
```
|
||||
|
||||
Clippy doit être relancé à chaque tranche :
|
||||
|
||||
```bash
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
## 0.7.47 acquis
|
||||
|
||||
- Upstream Git Registry ajouté.
|
||||
- Demo3 étendu : multi-target, multi-source, pagination, orderbook targets, burn/mint/transfer/wrap/unwrap/stake.
|
||||
- Demo2 backfill signature fonctionnel.
|
||||
- Replay local avec ledger.
|
||||
- OpenBook v2 decoder audit-only.
|
||||
- Phoenix v1 decoder audit-only.
|
||||
- Les decoders audit-only ne produisent aucun trade/candle.
|
||||
|
||||
## OpenBook v2
|
||||
|
||||
Program id :
|
||||
|
||||
```text
|
||||
opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb
|
||||
```
|
||||
|
||||
État :
|
||||
|
||||
```text
|
||||
audit-only local decoder
|
||||
upstream_git fallback cleaned
|
||||
Program data mapped:
|
||||
- FillLog
|
||||
- OpenOrdersPositionLog
|
||||
- TotalOrderFillEvent
|
||||
- SettleFundsLog
|
||||
trade_count = 0
|
||||
```
|
||||
|
||||
Ne pas activer de trade/candle tant que maker/taker/base/quote et les lots ne sont pas validés.
|
||||
|
||||
## Phoenix v1
|
||||
|
||||
Program id :
|
||||
|
||||
```text
|
||||
PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY
|
||||
```
|
||||
|
||||
État :
|
||||
|
||||
```text
|
||||
audit-only local decoder
|
||||
log instruction strict 0x0f
|
||||
events observed:
|
||||
- Reduce
|
||||
- Place
|
||||
- TimeInForce
|
||||
currentInstructionTag mappings:
|
||||
- 0x09 CancelUpToWithFreeFunds
|
||||
- 0x0c WithdrawFunds
|
||||
- 0x10 PlaceMultiplePostOnlyOrders
|
||||
trade_count = 0
|
||||
```
|
||||
|
||||
Prochaine action préférée : finir Phoenix v1 avec tous les events disponibles dans les sources Git/IDL, mais rester audit-only jusqu’à validation économique.
|
||||
|
||||
## Contraintes
|
||||
|
||||
- Rust 2024.
|
||||
- Pas de `mod.rs`.
|
||||
- Fichiers Rust avec entête `// file: ...`.
|
||||
- Exposition centralisée via `lib.rs`.
|
||||
- `#![deny(unreachable_pub)]`, `#![warn(missing_docs)]`.
|
||||
- Pas de `anyhow`.
|
||||
- Pas de `thiserror`.
|
||||
- Pas de `?`, `unwrap`, `expect` dans le code applicatif.
|
||||
- Utiliser `match`, `if let Err`, `let Err = ... else`.
|
||||
- Si une requête DB est ajoutée/modifiée, mettre à jour `kb_lib/src/db.rs`, puis `kb_lib/src/lib.rs` si nécessaire.
|
||||
|
||||
## Méthode par DEX/version
|
||||
|
||||
Pour chaque DEX/version :
|
||||
|
||||
1. inspecter Carbon + autres sources Git/IDL ;
|
||||
2. lister tous les discriminants instructions/events ;
|
||||
3. compléter `upstream_registry` / matrice si nécessaire ;
|
||||
4. utiliser Demo3 pour corpus ;
|
||||
5. backfill Demo2 ;
|
||||
6. replay forcé ;
|
||||
7. valider SQL ;
|
||||
8. ajouter decoder audit-only ou materialized selon preuve ;
|
||||
9. supprimer les doublons `upstream_git.instruction_match` si decoder spécialisé ;
|
||||
10. ne jamais produire trade/candle sans montants exploitables et sens économique validé.
|
||||
|
||||
## Requêtes de sécurité audit-only
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
de.protocol_name,
|
||||
de.event_kind,
|
||||
COUNT(te.id) AS trade_count
|
||||
FROM k_sol_dex_decoded_events de
|
||||
LEFT JOIN k_sol_trade_events te
|
||||
ON te.decoded_event_id = de.id
|
||||
WHERE de.protocol_name IN ('openbook_v2', 'phoenix_v1')
|
||||
GROUP BY de.protocol_name, de.event_kind
|
||||
ORDER BY trade_count DESC;
|
||||
```
|
||||
|
||||
Attendu :
|
||||
|
||||
```text
|
||||
trade_count = 0
|
||||
```
|
||||
|
||||
## Livrable attendu
|
||||
|
||||
Pour chaque tranche :
|
||||
|
||||
- fichiers ajoutés/modifiés seulement ;
|
||||
- archive zip ;
|
||||
- commandes de test ;
|
||||
- requêtes SQL ;
|
||||
- notes sur ce qui reste non vérifié ;
|
||||
- ne pas prétendre qu’un event ou program id est vérifié sans corpus local.
|
||||
155
NEXT_SESSION_PROMPT_0.7.47_EVENT_COVERAGE_V3.md
Normal file
155
NEXT_SESSION_PROMPT_0.7.47_EVENT_COVERAGE_V3.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# Prompt de reprise — khadhroony-bobobot `0.7.47-1FE5` / Event coverage
|
||||
|
||||
Reprise du projet `khadhroony-bobobot`.
|
||||
|
||||
## Archive de départ
|
||||
|
||||
Utiliser :
|
||||
|
||||
```text
|
||||
khadhroony-bobobot-v0.7.47-1FE5-full.zip
|
||||
```
|
||||
|
||||
Et les docs :
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
DEX_DECODER_MATRIX.md
|
||||
DEX_EVENT_COVERAGE_MATRIX.md
|
||||
DB_EVENT_MODEL_REVIEW.md
|
||||
```
|
||||
|
||||
## Décision de reprise
|
||||
|
||||
Ne pas essayer de “faire tous les events de tous les DEX” dans une seule session.
|
||||
|
||||
La stratégie est maintenant :
|
||||
|
||||
```text
|
||||
un DEX/version = une tranche
|
||||
tous les events listés = audit coverage
|
||||
matérialisation seulement après corpus + SQL + invariants
|
||||
```
|
||||
|
||||
## Sources Git/IDL à utiliser systématiquement
|
||||
|
||||
- https://github.com/sevenlabs-hq/carbon/tree/main/decoders
|
||||
- https://github.com/0xfnzero/solana-streamer
|
||||
- https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl
|
||||
- https://github.com/pinax-network/substreams-solana-idls/tree/main/src
|
||||
- https://github.com/hodlwarden/solana-tx-parser/tree/main/src
|
||||
- https://github.com/openbook-dex/openbook-v2
|
||||
- https://github.com/all-in-one-blockchain/phoenix-onchain-mm
|
||||
- https://docs.vybenetwork.com/docs/available-dexs-amms
|
||||
|
||||
## Objectif événementiel
|
||||
|
||||
Décoder le maximum d’events, pas seulement les swaps.
|
||||
|
||||
Inclure explicitement :
|
||||
|
||||
```text
|
||||
swap
|
||||
pool_create
|
||||
add_liquidity
|
||||
remove_liquidity
|
||||
position_open
|
||||
position_close
|
||||
fee
|
||||
reward
|
||||
admin/config
|
||||
mint
|
||||
burn
|
||||
transfer
|
||||
account_create
|
||||
account_close
|
||||
wrap_sol
|
||||
unwrap_sol
|
||||
order_place
|
||||
order_cancel
|
||||
order_fill
|
||||
consume_events
|
||||
settle_funds
|
||||
vault_deposit
|
||||
vault_withdraw
|
||||
lock
|
||||
unlock
|
||||
launch
|
||||
migration
|
||||
stake
|
||||
unstake
|
||||
unknown/unmapped audit
|
||||
```
|
||||
|
||||
Raison : burn, perte de liquidité, changements admin/config, vault withdraw, migration, mint anormal, close account, etc. peuvent influencer une décision de trading même si ce ne sont pas des trades.
|
||||
|
||||
## Base de données
|
||||
|
||||
La base actuelle suffit pour audit-only via `k_sol_dex_decoded_events`, mais elle n’est pas suffisante pour tout exploiter en requêtes métier.
|
||||
|
||||
À considérer avant ou pendant `0.7.48` :
|
||||
|
||||
```text
|
||||
k_sol_dex_event_coverage_entries
|
||||
k_sol_token_transfer_events
|
||||
k_sol_token_account_events
|
||||
k_sol_orderbook_events
|
||||
k_sol_vault_events
|
||||
k_sol_launch_events
|
||||
k_sol_liquidity_lock_events
|
||||
```
|
||||
|
||||
Priorité minimale :
|
||||
|
||||
```text
|
||||
1. k_sol_dex_event_coverage_entries
|
||||
2. k_sol_token_transfer_events
|
||||
3. k_sol_orderbook_events
|
||||
```
|
||||
|
||||
## Ordre des versions
|
||||
|
||||
```text
|
||||
0.7.48-pre event coverage + DB model checkpoint
|
||||
0.7.48 raydium_cpmm
|
||||
0.7.49 raydium_clmm
|
||||
0.7.50 pump_swap
|
||||
0.7.51 pump_fun
|
||||
0.7.52 meteora_dbc
|
||||
0.7.53 meteora_dlmm
|
||||
0.7.54 meteora_damm_v1
|
||||
0.7.55 meteora_damm_v2
|
||||
0.7.56 phoenix_v1
|
||||
0.7.57 openbook_v2
|
||||
0.7.58 orca_whirlpools
|
||||
0.7.59 launch surfaces
|
||||
0.7.60 DEX historiques/candidats
|
||||
0.7.61 validation consolidée
|
||||
```
|
||||
|
||||
## Règles fixes
|
||||
|
||||
- Un event non-trade ne produit jamais trade/candle.
|
||||
- Une transaction failed reste audit, jamais trade/candle.
|
||||
- Un discriminator upstream n’est pas une preuve métier.
|
||||
- Un program id upstream n’est pas vérifié sans corpus local.
|
||||
- Chaque decoder spécialisé doit remplacer le fallback `upstream_git.instruction_match` pour éviter les doublons.
|
||||
- Tout event connu mais non observé reste `upstream_git_mapped_unverified`.
|
||||
- Tout event observé mais non matérialisé reste audit-only ou decoded, pas materialized.
|
||||
|
||||
## Prochaine tâche recommandée
|
||||
|
||||
Commencer par :
|
||||
|
||||
```text
|
||||
0.7.48-pre — event coverage + DB model checkpoint
|
||||
```
|
||||
|
||||
Livrables attendus :
|
||||
|
||||
1. ajouter/documenter une table de couverture event/discriminator ;
|
||||
2. générer un rapport de couverture par DEX/version ;
|
||||
3. préparer `raydium_cpmm` avec la liste complète des events depuis Carbon/fnzero/IDL ;
|
||||
4. ne pas changer encore la matérialisation trade/candle.
|
||||
249
NEXT_SESSION_PROMPT_0.7.47_UPSTREAM_REGISTRY.md
Normal file
249
NEXT_SESSION_PROMPT_0.7.47_UPSTREAM_REGISTRY.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# Prompt de reprise — khadhroony-bobobot `0.7.47`
|
||||
|
||||
Reprise du projet `khadhroony-bobobot`.
|
||||
|
||||
## Contexte
|
||||
|
||||
Le workspace contient principalement :
|
||||
|
||||
- `kb_lib` : logique métier Solana/DEX, clients HTTP/WS, décodage, détection, SQLite, replay, validation, diagnostics, metadata, candles, signaux ;
|
||||
- `kb_demo_app` : application Tauri V2 de démo/inspection. Elle doit rester une façade UI et ne pas contenir de logique métier DEX profonde.
|
||||
|
||||
La version `0.7.46` est clôturée sur `meteora_damm_v1`.
|
||||
|
||||
## État validé à la fin de `0.7.46`
|
||||
|
||||
- `cargo test -p kb_lib` : vert.
|
||||
- `cargo clippy -p kb_lib --all-targets -- -D warnings` : vert.
|
||||
- Demo2 et Demo3 fonctionnent bien pour backfill et discovery.
|
||||
- Demo3 supporte :
|
||||
- multi-target ;
|
||||
- multi-source ;
|
||||
- pagination `before` / `until` ;
|
||||
- `max_pages` ;
|
||||
- `newest_first` / `oldest_first`.
|
||||
- Le replay local supporte le ledger de décodage/replay et les options `skipDexDecode` / `forceDexDecode`.
|
||||
- `meteora_damm_v1` couvre les surfaces observées localement :
|
||||
- `swap` ;
|
||||
- `claim_fee` ;
|
||||
- `create_lock_escrow` ;
|
||||
- `lock_liquidity` ;
|
||||
- `remove_liquidity` ;
|
||||
- `add_liquidity` ;
|
||||
- `create_pool`.
|
||||
- Les statuts/payloads ne doivent plus utiliser une terminologie spécifique à un dépôt externe particulier.
|
||||
- Les statuts génériques attendus sont :
|
||||
- `upstream_git_unverified` ;
|
||||
- `upstream_git_mapped_unverified` ;
|
||||
- `upstream_git_local_corpus_observed` ;
|
||||
- `upstream_git_local_corpus_materialized` ;
|
||||
- `upstream_git_layout_unverified` si le layout est connu depuis une source Git mais pas encore validé localement.
|
||||
|
||||
## Décision base de données pour `0.7.47`
|
||||
|
||||
La version `0.7.46` est considérée finalisée. Ne pas demander ni proposer de replay forcé de l’ancienne base `0.7.46` pour clôturer cette version, sauf demande explicite.
|
||||
|
||||
Pour `0.7.47`, le développement et la validation doivent se faire de préférence sur une **nouvelle base SQLite dédiée**. Cette base servira à constituer un corpus propre avec Demo3 et Demo2 sur plusieurs paires, pools ou programmes de DEX différents.
|
||||
|
||||
Règles pratiques :
|
||||
|
||||
- l’ancienne base `0.7.46` peut servir de référence historique ou de comparaison, mais elle ne doit pas être migrée ou redécodée automatiquement ;
|
||||
- si une validation DB est nécessaire en `0.7.47`, elle doit cibler la nouvelle base de travail `0.7.47` ;
|
||||
- les backfills `0.7.47` doivent être construits à partir de Demo3 discovery puis Demo2 signature/pool backfill ;
|
||||
- le replay local reste utile, mais seulement après constitution du corpus `0.7.47`, pas comme étape de finalisation de `0.7.46` ;
|
||||
- les entrées du registre upstream Git restent des indices tant qu’elles ne sont pas observées sur cette nouvelle base ou sur un corpus explicitement indiqué.
|
||||
|
||||
## Objectif de `0.7.47`
|
||||
|
||||
`0.7.47` est dédiée à :
|
||||
|
||||
```text
|
||||
Upstream Git Registry / DEX discovery preparation
|
||||
```
|
||||
|
||||
L’objectif n’est pas de valider directement un DEX unique. L’objectif est de créer un registre générique permettant d’indexer les `program_id`, discriminants d’instructions, discriminants d’events, noms d’instructions, familles de programmes et types de surfaces issus de dépôts Git externes de decoders Solana.
|
||||
|
||||
Ces entrées sont des **indices de découverte**, pas des preuves métier. Elles doivent rester non vérifiées tant qu’elles ne sont pas confirmées par :
|
||||
|
||||
1. Demo3 discovery ;
|
||||
2. backfill signature/pool via Demo2 ;
|
||||
3. replay local sur la base de travail `0.7.47` ;
|
||||
4. requêtes SQL de validation sur cette même base ;
|
||||
5. invariants métier : pas de faux trade, pas de fausse candle, pas de promotion de `program_id` sans corpus.
|
||||
|
||||
## Noms recommandés
|
||||
|
||||
Modules possibles :
|
||||
|
||||
```text
|
||||
kb_lib/src/upstream_registry.rs
|
||||
kb_lib/src/upstream_registry_types.rs
|
||||
kb_lib/src/upstream_registry_match.rs
|
||||
kb_lib/src/upstream_registry_generated.rs
|
||||
```
|
||||
|
||||
Nom fonctionnel :
|
||||
|
||||
```text
|
||||
Upstream Git Registry
|
||||
```
|
||||
|
||||
Ne pas utiliser de nom de dépôt externe spécifique dans les noms publics, les statuts, les tables ou les payloads métier.
|
||||
|
||||
## Première tranche attendue
|
||||
|
||||
Créer une première version statique du registre dans `kb_lib`, sans modifier la DB si ce n’est pas nécessaire.
|
||||
|
||||
Chaque entrée de registre devrait contenir au minimum :
|
||||
|
||||
```text
|
||||
source_repo
|
||||
source_path
|
||||
decoder_code
|
||||
program_id
|
||||
program_family
|
||||
surface_kind
|
||||
entry_kind = instruction | event | account | program
|
||||
entry_name
|
||||
discriminator_hex
|
||||
discriminator_len
|
||||
proof_status
|
||||
notes
|
||||
```
|
||||
|
||||
Les entrées de registre doivent être exposées à `kb_demo_app` via une commande Demo3 ou une commande dédiée, mais la logique reste dans `kb_lib`.
|
||||
|
||||
## Familles à indexer en priorité
|
||||
|
||||
DEX / AMM / CLMM / orderbook :
|
||||
|
||||
```text
|
||||
meteora-damm-v2
|
||||
meteora-dbc
|
||||
meteora-dlmm
|
||||
meteora-vault
|
||||
raydium-amm-v4
|
||||
raydium-clmm
|
||||
raydium-cpmm
|
||||
raydium-launchpad
|
||||
raydium-liquidity-locking
|
||||
raydium-stable-swap
|
||||
orca-whirlpool
|
||||
fluxbeam
|
||||
lifinity-amm-v2
|
||||
phoenix-v1
|
||||
openbook-v2
|
||||
stabble-stable-swap
|
||||
stabble-weighted-swap
|
||||
bonkswap
|
||||
boop
|
||||
moonshot
|
||||
heaven
|
||||
okx-dex
|
||||
pancake-swap
|
||||
vertigo
|
||||
virtuals
|
||||
wavebreak
|
||||
onchain-labs-dex-v1
|
||||
onchain-labs-dex-v2
|
||||
```
|
||||
|
||||
Agrégateurs / ordres / perps / lending :
|
||||
|
||||
```text
|
||||
jupiter-swap
|
||||
jupiter-dca
|
||||
jupiter-limit-order
|
||||
jupiter-limit-order-2
|
||||
jupiter-perpetuals
|
||||
jupiter-lend
|
||||
kamino-lending
|
||||
kamino-vault
|
||||
kamino-farms
|
||||
kamino-limit-order
|
||||
drift-v2
|
||||
marginfi-v2
|
||||
dflow-aggregator-v4
|
||||
zeta
|
||||
```
|
||||
|
||||
Contexte transactionnel non DEX :
|
||||
|
||||
```text
|
||||
system-program
|
||||
token-program
|
||||
token-2022
|
||||
associated-token-account
|
||||
address-lookup-table
|
||||
memo-program
|
||||
stake-program
|
||||
mpl-token-metadata
|
||||
mpl-core
|
||||
bubblegum
|
||||
name-service
|
||||
marinade-finance
|
||||
solayer-restaking-program
|
||||
swig
|
||||
sharky
|
||||
circle-message-transmitter-v2
|
||||
circle-token-messenger-v2
|
||||
```
|
||||
|
||||
## Règles de validation
|
||||
|
||||
- Une entrée upstream Git reste `upstream_git_unverified` tant qu’elle n’a pas été vue localement.
|
||||
- Une entrée branchée dans un decoder mais jamais vue localement reste `upstream_git_mapped_unverified`.
|
||||
- Une entrée vue après Demo3/backfill/replay peut devenir `upstream_git_local_corpus_observed`.
|
||||
- Une entrée qui alimente correctement une table métier dédiée peut devenir `upstream_git_local_corpus_materialized`.
|
||||
- Aucun `program_id`, event ou discriminator ne doit être déclaré vérifié uniquement parce qu’il existe dans un dépôt Git externe.
|
||||
- Aucun event non-trade ne doit produire trade, metric ou candle.
|
||||
|
||||
## Contraintes de code
|
||||
|
||||
- Rust 2024.
|
||||
- Pas de `mod.rs`.
|
||||
- Fichiers Rust avec entête `// file: ...`.
|
||||
- Fichiers `.toml` avec entête `# file: ...`.
|
||||
- Exposition centralisée via `lib.rs`.
|
||||
- `#![deny(unreachable_pub)]` et `#![warn(missing_docs)]`.
|
||||
- Pas de `anyhow`.
|
||||
- Pas de `thiserror`.
|
||||
- Pas de `?`, `unwrap`, `expect` dans le code applicatif.
|
||||
- Utiliser `match`, `if let Err`, `let Err = ... else`.
|
||||
- Tests verts à chaque étape.
|
||||
- Si une requête DB est ajoutée/modifiée, mettre à jour les re-exports dans `kb_lib/src/db.rs`, puis `kb_lib/src/lib.rs` si nécessaire.
|
||||
|
||||
## Format de livraison attendu
|
||||
|
||||
Pour chaque tranche :
|
||||
|
||||
1. expliquer brièvement les fichiers touchés ;
|
||||
2. fournir une archive des fichiers ajoutés/modifiés seulement, avec l’arborescence du projet ;
|
||||
3. indiquer les commandes de test à lancer ;
|
||||
4. indiquer les requêtes SQL utiles si validation DB nécessaire ;
|
||||
5. ne jamais prétendre qu’un `program_id` ou un event est vérifié sans preuve/corpus.
|
||||
|
||||
|
||||
dexlab
|
||||
bags / letsbonk / bonk_fun
|
||||
believe
|
||||
moonit
|
||||
launchbeam
|
||||
metadao / metaDAO
|
||||
printr
|
||||
zora
|
||||
aldrin
|
||||
aldrin_v2
|
||||
crema
|
||||
cropper
|
||||
cropper_legacy
|
||||
guacswap
|
||||
invariant
|
||||
lifinity_v1
|
||||
openbook_v1 / serum-style legacy
|
||||
orca_v1
|
||||
orca_v2
|
||||
saber
|
||||
saros
|
||||
serum_v3
|
||||
token_swap
|
||||
50
README.md
50
README.md
@@ -6,6 +6,44 @@
|
||||
|
||||
Ce document reflète le point de reprise `0.7.43-E5C` et l’état de consolidation atteint après `0.7.45` pour `meteora_dlmm`. La version Cargo a évolué ensuite à `0.7.46` côté workspace. Le lot Meteora initialement ouvert en bloc a été redécoupé : `meteora_dlmm` est traité séparément, puis la suite reprend `meteora_damm_v1`, `meteora_damm_v2` et `meteora_dbc` un par un.
|
||||
|
||||
|
||||
## État de reprise actuel `0.7.47-1FE5`
|
||||
|
||||
Le point de reprise courant n’est plus `0.7.43-E5C`. La branche de travail actuelle est `0.7.47-1FE5` : le registre upstream Git est en place, OpenBook v2 et Phoenix v1 disposent de decoders locaux **audit-only**, et la suite doit être conduite par DEX/version au lieu de tenter tous les events en une seule session.
|
||||
|
||||
Les nouveaux chemins audit-only doivent rester non matérialisants : aucun event OpenBook v2 ou Phoenix v1 ne doit produire de trade, metric ou candle tant que le sens économique complet n’est pas validé.
|
||||
|
||||
Voir aussi :
|
||||
|
||||
- `DEX_DECODER_MATRIX.md` pour la matrice DEX détaillée ;
|
||||
- `ROADMAP.md` pour le plan révisé `0.7.48` à `0.7.61` ;
|
||||
- `CHANGELOG.md` pour les tranches `0.7.47-*`.
|
||||
|
||||
|
||||
## Sources upstream Git / IDL à utiliser en `0.7.47+`
|
||||
|
||||
Les sources externes ci-dessous sont des **indices de décodage**, pas des preuves métier. Elles servent à extraire des `program_id`, discriminants, IDL, layouts et noms d’instructions/events, mais toute promotion locale doit rester conditionnée à :
|
||||
|
||||
1. observation Demo3 ;
|
||||
2. backfill Demo2 ;
|
||||
3. replay local sur la base de travail ;
|
||||
4. requêtes SQL de validation ;
|
||||
5. invariants : aucun faux trade, aucune fausse candle, aucun `program_id` promu sans corpus.
|
||||
|
||||
Sources prioritaires :
|
||||
|
||||
| Source | Usage attendu |
|
||||
|---|---|
|
||||
| `https://github.com/sevenlabs-hq/carbon/tree/main/decoders` | Source principale de discriminants, instructions et events multi-protocoles. |
|
||||
| `https://github.com/0xfnzero/solana-streamer` | Source complémentaire pour PumpFun, PumpSwap, Bonk et Raydium CPMM. |
|
||||
| `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl` | IDL complémentaires pour programmes Solana supportés par parser SDK. |
|
||||
| `https://github.com/pinax-network/substreams-solana-idls/tree/main/src` | IDL et layouts additionnels à comparer au registre local. |
|
||||
| `https://github.com/hodlwarden/solana-tx-parser/tree/main/src` | Décodage transactionnel complémentaire et conventions de mapping. |
|
||||
| `https://github.com/openbook-dex/openbook-v2` | Source officielle OpenBook v2 : programme, IDL et logs. |
|
||||
| `https://github.com/all-in-one-blockchain/phoenix-onchain-mm` | Source Phoenix/MM complémentaire pour corpus et intégration. |
|
||||
| `https://docs.vybenetwork.com/docs/available-dexs-amms` | Source de découverte de DEX/AMM supportés par Vybe, à traiter comme index externe non vérifié localement. |
|
||||
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
L’objectif opérationnel est de construire progressivement une application capable de :
|
||||
@@ -388,3 +426,15 @@ La version `0.7.47` n’est plus dédiée à un seul DEX. Elle doit introduire u
|
||||
Les entrées de ce registre sont des indices de découverte, pas des preuves métier. Elles doivent être marquées `upstream_git_unverified` ou `upstream_git_mapped_unverified` tant qu’elles ne sont pas confirmées par Demo3, backfill, replay local et requêtes SQL.
|
||||
|
||||
Le registre sert à accélérer la constitution de corpus pour les DEX et surfaces suivantes : Meteora DAMM v2/DBC/Vault, Raydium Launchpad/Stable/Locking, Orca Whirlpools, FluxBeam, DexLab, Lifinity AMM v2, Phoenix/OpenBook, Stabble, BonkSwap, Boop, Moonshot, Heaven, Wavebreak, Vertigo, Virtuals, Pancake Swap, OKX DEX, Jupiter/Kamino/Drift et autres programmes utiles à la découverte.
|
||||
|
||||
|
||||
## Note 0.7.47-1FE5 — Event coverage et modèle DB
|
||||
|
||||
La matrice DEX/version doit être complétée par une matrice événementielle exhaustive. Le projet ne vise pas seulement les swaps : les events `burn`, `mint`, `transfer`, `account_close`, `lock/unlock`, `vault_deposit/withdraw`, `admin/config`, `order_fill`, `settle_funds`, `launch` et `migration` peuvent influencer une décision de trading.
|
||||
|
||||
Voir :
|
||||
|
||||
- `DEX_DECODER_MATRIX.md` pour le statut par DEX/version ;
|
||||
- `DEX_EVENT_COVERAGE_MATRIX.md` pour les familles d'events à couvrir ;
|
||||
- `DB_EVENT_MODEL_REVIEW.md` pour les ajouts DB à envisager avant `0.7.48+`.
|
||||
|
||||
|
||||
64
ROADMAP.md
64
ROADMAP.md
@@ -2,6 +2,55 @@
|
||||
|
||||
# khadhroony-bobobot — Roadmap
|
||||
|
||||
## 0.7.47-1FE5 — Décision de planification : ne plus viser “tous les events en une session”
|
||||
|
||||
La phase `0.7.47` a montré que l’objectif “réimplémenter tous les décodeurs Carbon et toutes les sources en un seul bloc” est trop large. Le plan est donc redécoupé en **un DEX/version par tranche**, avec une matrice documentaire dédiée : `DEX_DECODER_MATRIX.md`.
|
||||
|
||||
Règles de planification :
|
||||
|
||||
- chaque DEX/version doit avoir sa propre phase de corpus ;
|
||||
- chaque phase doit lister explicitement les sources Git/IDL consultées ;
|
||||
- tous les events/instructions disponibles dans les sources doivent être inventoriés, même si seuls certains deviennent matérialisés ;
|
||||
- le statut par event doit rester séparé : `upstream_git_unverified`, `upstream_git_mapped_unverified`, `upstream_git_local_corpus_observed`, `audit-only`, `materialized` ;
|
||||
- un decoder local spécialisé peut remplacer `upstream_git.instruction_match`, mais ne doit pas créer de trade/candle sans validation de montants et de sens économique ;
|
||||
- OpenBook v2 et Phoenix v1 restent `audit-only` à ce stade, malgré leurs layouts partiellement décodés.
|
||||
|
||||
### Sources upstream obligatoires à vérifier
|
||||
|
||||
| Source | Usage |
|
||||
|---|---|
|
||||
| `https://github.com/sevenlabs-hq/carbon/tree/main/decoders` | Source principale des decoders multi-protocoles. |
|
||||
| `https://github.com/0xfnzero/solana-streamer` | Source complémentaire PumpFun/PumpSwap/Bonk/Raydium CPMM. |
|
||||
| `https://github.com/0xfnzero/sol-parser-sdk/tree/main/idl` | IDL complémentaires. |
|
||||
| `https://github.com/pinax-network/substreams-solana-idls/tree/main/src` | IDL et layouts additionnels. |
|
||||
| `https://github.com/hodlwarden/solana-tx-parser/tree/main/src` | Parsers transactionnels complémentaires. |
|
||||
| `https://github.com/openbook-dex/openbook-v2` | Source officielle OpenBook v2. |
|
||||
| `https://github.com/all-in-one-blockchain/phoenix-onchain-mm` | Source Phoenix/MM complémentaire. |
|
||||
| `https://docs.vybenetwork.com/docs/available-dexs-amms` | Source externe de découverte DEX/AMM, non vérifiante. |
|
||||
|
||||
### Plan révisé `0.7.48` à `0.7.61`
|
||||
|
||||
| Version cible | Scope | Objectif de clôture |
|
||||
|---|---|---|
|
||||
| `0.7.48` | `raydium_cpmm` | Reprendre tous les discriminants/events depuis Carbon/Solana Streamer ; vérifier swaps, liquidity, fees/admin ; confirmer matérialisation trade/candle et non-trade. |
|
||||
| `0.7.49` | `raydium_clmm` | Couvrir toutes les instructions CLMM : swaps, positions, liquidity, fees/rewards, Token-2022 ; valider matérialisation non-trade. |
|
||||
| `0.7.50` | `pump_swap` | Couvrir `buy/sell` et tous les events auxiliaires disponibles : fees, cashback, volume accumulator, admin/config. |
|
||||
| `0.7.51` | `pump_fun` | Traiter launch/bonding/migration ; séparer création token, buy/sell bonding, migration vers DEX effectif. |
|
||||
| `0.7.52` | `meteora_dbc` | Couverture DBC : bonding curve, swap, migration, launch attribution, fees/admin, non-trade. |
|
||||
| `0.7.53` | `meteora_dlmm` | Audit final de parité avec sources Git/IDL ; fermer ou documenter les audits résiduels. |
|
||||
| `0.7.54` | `meteora_damm_v1` | Parité upstream complète ; résoudre les cas non matérialisés faute de pool/pair quand possible. |
|
||||
| `0.7.55` | `meteora_damm_v2` | Couverture DAMM v2 complète : create, swap, liquidity, fees/admin/config ; décider trade actionability. |
|
||||
| `0.7.56` | `phoenix_v1` | Finir tous les events Git disponibles en audit ; préparer mais ne pas activer trade materialization. |
|
||||
| `0.7.57` | `openbook_v2` | Finir layouts logs/events ; définir conditions futures de trade/candle sans les activer par défaut. |
|
||||
| `0.7.58` | `orca_whirlpools` | Reprendre Whirlpools depuis IDL/source : swaps, pools, positions, liquidity, fees/rewards. |
|
||||
| `0.7.59` | Launch surfaces | Raydium LaunchLab/Launchpad, PumpFun migration, Moonshot/Moonit, Boop, Heaven, Bags, LetsBonk. |
|
||||
| `0.7.60` | DEX historiques / candidats | FluxBeam, DexLab, Lifinity, Stabble, BonkSwap, GooseFX, Obric, SolFi, etc. par corpus. |
|
||||
| `0.7.61` | Validation consolidée | Rejouer une base neuve multi-DEX, vérifier matrice, zéro faux trade/candle, rapport de couverture par DEX/event. |
|
||||
|
||||
Ce plan remplace les anciens regroupements larges `0.7.50+` qui mélangeaient plusieurs DEX dans une même version.
|
||||
|
||||
|
||||
|
||||
## 1. Objet du projet
|
||||
|
||||
`khadhroony-bobobot` est un workspace Rust destiné à la détection, l’observation, l’analyse de patterns et, à terme, à l’exécution semi-automatisée d’achats/ventes de tokens sur la blockchain Solana.
|
||||
@@ -1188,6 +1237,21 @@ Familles prioritaires à indexer en premier :
|
||||
|
||||
Aucun de ces programmes ne doit être marqué `verified_by_corpus` uniquement parce qu’il existe dans un dépôt Git externe.
|
||||
|
||||
|
||||
### 6.079B. Version `0.7.48-pre` — Event coverage et checkpoint DB
|
||||
|
||||
Objectif : éviter de limiter la matrice aux DEX/versions et imposer une couverture événementielle exhaustive avant la reprise DEX par DEX.
|
||||
|
||||
À faire :
|
||||
|
||||
- maintenir `DEX_EVENT_COVERAGE_MATRIX.md` en plus de `DEX_DECODER_MATRIX.md` ;
|
||||
- lister pour chaque DEX/version tous les events/instructions/logs connus depuis Carbon, fnzero, IDL, Pinax, HODL Warden, OpenBook, Phoenix et Vybe ;
|
||||
- inclure explicitement les familles non-trade : `burn`, `mint`, `transfer`, `account_create`, `account_close`, `wrap_sol`, `unwrap_sol`, `lock`, `unlock`, `vault_deposit`, `vault_withdraw`, `admin/config`, `fee`, `reward`, `launch`, `migration` ;
|
||||
- vérifier si la DB actuelle suffit ou si une table transversale doit être ajoutée ;
|
||||
- prioriser `k_sol_dex_event_coverage_entries`, puis `k_sol_token_transfer_events` et `k_sol_orderbook_events` ;
|
||||
- ne pas créer de trade/candle depuis ces nouveaux chemins sans validation économique et corpus.
|
||||
|
||||
|
||||
### 6.080. Version `0.7.48` — `meteora_damm_v2` séparé
|
||||
Objectif : reprendre `meteora_damm_v2` comme DEX effectif séparé après disponibilité du registre upstream Git.
|
||||
|
||||
|
||||
@@ -138,13 +138,85 @@
|
||||
<input id="demo3TargetPoolAdminInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="pool_admin" />
|
||||
<label for="demo3TargetPoolAdminInput" class="form-check-label">pool_admin</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetBurnInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="burn" />
|
||||
<label for="demo3TargetBurnInput" class="form-check-label">burn</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetMintInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="mint" />
|
||||
<label for="demo3TargetMintInput" class="form-check-label">mint</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetTransferInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="transfer" />
|
||||
<label for="demo3TargetTransferInput" class="form-check-label">transfer</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetCloseAccountInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="close_account" />
|
||||
<label for="demo3TargetCloseAccountInput" class="form-check-label">close_account</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetTokenAccountCreateInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="token_account_create" />
|
||||
<label for="demo3TargetTokenAccountCreateInput" class="form-check-label">token_account_create</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetWrapSolInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="wrap_sol" />
|
||||
<label for="demo3TargetWrapSolInput" class="form-check-label">wrap_sol</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetUnwrapSolInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="unwrap_sol" />
|
||||
<label for="demo3TargetUnwrapSolInput" class="form-check-label">unwrap_sol</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetStakeInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="stake" />
|
||||
<label for="demo3TargetStakeInput" class="form-check-label">stake</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetUnstakeInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="unstake" />
|
||||
<label for="demo3TargetUnstakeInput" class="form-check-label">unstake</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetOrderPlaceInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="order_place" />
|
||||
<label for="demo3TargetOrderPlaceInput" class="form-check-label">order_place</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetOrderCancelInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="order_cancel" />
|
||||
<label for="demo3TargetOrderCancelInput" class="form-check-label">order_cancel</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetOrderFillInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="order_fill" />
|
||||
<label for="demo3TargetOrderFillInput" class="form-check-label">order_fill</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetSettleFundsInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="settle_funds" />
|
||||
<label for="demo3TargetSettleFundsInput" class="form-check-label">settle_funds</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetConsumeEventsInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="consume_events" />
|
||||
<label for="demo3TargetConsumeEventsInput" class="form-check-label">consume_events</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetMarketCreateInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="market_create" />
|
||||
<label for="demo3TargetMarketCreateInput" class="form-check-label">market_create</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetOpenOrdersCreateInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="open_orders_create" />
|
||||
<label for="demo3TargetOpenOrdersCreateInput" class="form-check-label">open_orders_create</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetOpenOrdersCloseInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="open_orders_close" />
|
||||
<label for="demo3TargetOpenOrdersCloseInput" class="form-check-label">open_orders_close</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetCloseMarketInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="close_market" />
|
||||
<label for="demo3TargetCloseMarketInput" class="form-check-label">close_market</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="demo3TargetUnknownNonSwapInput" class="form-check-input" type="checkbox" name="demo3TargetEventInput" value="unknown_non_swap" />
|
||||
<label for="demo3TargetUnknownNonSwapInput" class="form-check-label">unknown_non_swap</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text">Leave all unchecked for generic discovery. Check several surfaces to scan once and keep candidates matching any selected target.</div>
|
||||
<div class="form-text">Use this to find corpus signatures for non-swap decoders without promoting unverified events.</div>
|
||||
<div class="form-text">Use this to find corpus signatures for non-swap decoders without promoting unverified events. Leave all unchecked to request target='any'.</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="demo3HttpRoleInput" class="form-label">HTTP role</label>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* One upstream registry entry exposed through Demo3.
|
||||
*/
|
||||
export type Demo3UpstreamRegistryEntry = {
|
||||
/**
|
||||
* Repository name or bootstrap locator that produced the entry.
|
||||
*/
|
||||
sourceRepo: string | null,
|
||||
/**
|
||||
* Repository-relative path or bootstrap path that produced the entry.
|
||||
*/
|
||||
sourcePath: string | null,
|
||||
/**
|
||||
* Stable decoder code used by the registry.
|
||||
*/
|
||||
decoderCode: string,
|
||||
/**
|
||||
* Optional Solana program id when already known by the source entry.
|
||||
*/
|
||||
programId: string | null,
|
||||
/**
|
||||
* Program family used to group related programs.
|
||||
*/
|
||||
programFamily: string,
|
||||
/**
|
||||
* Surface kind such as AMM, CLMM, launch, aggregator or core Solana.
|
||||
*/
|
||||
surfaceKind: string,
|
||||
/**
|
||||
* Entry kind: instruction, event, account or program.
|
||||
*/
|
||||
entryKind: string,
|
||||
/**
|
||||
* Source-level entry name.
|
||||
*/
|
||||
entryName: string,
|
||||
/**
|
||||
* Optional discriminator bytes encoded as lowercase hexadecimal.
|
||||
*/
|
||||
discriminatorHex: string | null,
|
||||
/**
|
||||
* Optional discriminator byte length.
|
||||
*/
|
||||
discriminatorLen: number | null,
|
||||
/**
|
||||
* Current proof status.
|
||||
*/
|
||||
proofStatus: string,
|
||||
/**
|
||||
* Notes that preserve uncertainty and validation requirements.
|
||||
*/
|
||||
notes: string, };
|
||||
@@ -0,0 +1,15 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Demo3UpstreamRegistryResult } from "./Demo3UpstreamRegistryResult";
|
||||
|
||||
/**
|
||||
* Payload returned by the Demo3 upstream registry command.
|
||||
*/
|
||||
export type Demo3UpstreamRegistryPayload = {
|
||||
/**
|
||||
* Pretty JSON representation of the registry result.
|
||||
*/
|
||||
resultJson: string,
|
||||
/**
|
||||
* Structured registry result.
|
||||
*/
|
||||
result: Demo3UpstreamRegistryResult, };
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Demo3UpstreamRegistryEntry } from "./Demo3UpstreamRegistryEntry";
|
||||
import type { Demo3UpstreamRegistrySearchRequest } from "./Demo3UpstreamRegistrySearchRequest";
|
||||
import type { Demo3UpstreamRegistrySummary } from "./Demo3UpstreamRegistrySummary";
|
||||
|
||||
/**
|
||||
* Structured upstream registry result exposed through Demo3.
|
||||
*/
|
||||
export type Demo3UpstreamRegistryResult = {
|
||||
/**
|
||||
* Normalized request used by kb_lib.
|
||||
*/
|
||||
request: Demo3UpstreamRegistrySearchRequest,
|
||||
/**
|
||||
* Registry summary.
|
||||
*/
|
||||
summary: Demo3UpstreamRegistrySummary,
|
||||
/**
|
||||
* Matching entries.
|
||||
*/
|
||||
entries: Array<Demo3UpstreamRegistryEntry>, };
|
||||
@@ -0,0 +1,34 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Search request for the static upstream registry exposed through Demo3.
|
||||
*/
|
||||
export type Demo3UpstreamRegistrySearchRequest = {
|
||||
/**
|
||||
* Optional decoder-code filter.
|
||||
*/
|
||||
decoderCode: string | null,
|
||||
/**
|
||||
* Optional program-id filter.
|
||||
*/
|
||||
programId: string | null,
|
||||
/**
|
||||
* Optional program-family filter.
|
||||
*/
|
||||
programFamily: string | null,
|
||||
/**
|
||||
* Optional surface-kind filter.
|
||||
*/
|
||||
surfaceKind: string | null,
|
||||
/**
|
||||
* Optional entry-kind filter.
|
||||
*/
|
||||
entryKind: string | null,
|
||||
/**
|
||||
* Optional proof-status filter.
|
||||
*/
|
||||
proofStatus: string | null,
|
||||
/**
|
||||
* Optional maximum number of entries to return.
|
||||
*/
|
||||
limit: number | null, };
|
||||
@@ -0,0 +1,58 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Summary of the upstream registry snapshot exposed through Demo3.
|
||||
*/
|
||||
export type Demo3UpstreamRegistrySummary = {
|
||||
/**
|
||||
* Total static registry entry count before filtering.
|
||||
*/
|
||||
totalEntryCount: number,
|
||||
/**
|
||||
* Returned entry count after filtering.
|
||||
*/
|
||||
returnedEntryCount: number,
|
||||
/**
|
||||
* Number of entries that have a program id.
|
||||
*/
|
||||
entriesWithProgramIdCount: number,
|
||||
/**
|
||||
* Number of entries that have a discriminator.
|
||||
*/
|
||||
entriesWithDiscriminatorCount: number,
|
||||
/**
|
||||
* Number of program-level seed entries.
|
||||
*/
|
||||
programEntryCount: number,
|
||||
/**
|
||||
* Number of instruction entries.
|
||||
*/
|
||||
instructionEntryCount: number,
|
||||
/**
|
||||
* Number of event entries.
|
||||
*/
|
||||
eventEntryCount: number,
|
||||
/**
|
||||
* Number of account entries.
|
||||
*/
|
||||
accountEntryCount: number,
|
||||
/**
|
||||
* Number of entries still unverified from upstream Git or seed data.
|
||||
*/
|
||||
upstreamGitUnverifiedCount: number,
|
||||
/**
|
||||
* Number of entries mapped into decoders but not locally observed.
|
||||
*/
|
||||
upstreamGitMappedUnverifiedCount: number,
|
||||
/**
|
||||
* Number of entries observed in the local corpus.
|
||||
*/
|
||||
upstreamGitLocalCorpusObservedCount: number,
|
||||
/**
|
||||
* Number of entries materialized in local business tables.
|
||||
*/
|
||||
upstreamGitLocalCorpusMaterializedCount: number,
|
||||
/**
|
||||
* Number of layout entries still unverified locally.
|
||||
*/
|
||||
upstreamGitLayoutUnverifiedCount: number, };
|
||||
@@ -36,6 +36,22 @@ const presets: Demo3Preset[] = [
|
||||
{ label: "Meteora DBC", dexCode: "meteora_dbc", programId: "dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN", description: "Meteora DBC." },
|
||||
{ label: "Orca Whirlpools", dexCode: "orca_whirlpools", programId: "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc", description: "Orca Whirlpools CLMM." },
|
||||
{ label: "FluxBeam", dexCode: "fluxbeam", programId: "FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X", description: "FluxBeam." },
|
||||
{ label: "GooseFX V1 (Vybe)", dexCode: "goosefx_v1", programId: "GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Obric V2 (Vybe)", dexCode: "obric_v2", programId: "obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Ondo Global Market (Vybe)", dexCode: "ondo_global_market", programId: "XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Scorch (Vybe)", dexCode: "scorch", programId: "SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "ZeroFi (Vybe)", dexCode: "zerofi", programId: "ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Manifest CLOB (Vybe)", dexCode: "manifest_clob", programId: "MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms", description: "Entrée Vybe orderbook; à vérifier par corpus local." },
|
||||
{ label: "AlphaQ (Vybe)", dexCode: "alphaq", programId: "ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Goonfi (Vybe)", dexCode: "goonfi", programId: "goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Goonfi V2 (Vybe)", dexCode: "goonfi_v2", programId: "goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Byreal (Vybe)", dexCode: "byreal", programId: "REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "BisonFi (Vybe)", dexCode: "bisonfi", programId: "BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "FusionAMM (Vybe)", dexCode: "fusionamm", programId: "fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Woofi (Vybe)", dexCode: "woofi", programId: "WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Aquifer (Vybe)", dexCode: "aquifer", programId: "AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "Humidifi (Vybe)", dexCode: "humidifi", programId: "9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "SolFi V2 (Vybe)", dexCode: "solfi_v2", programId: "SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF", description: "Entrée Vybe; à vérifier par corpus local." },
|
||||
{ label: "DexLab", dexCode: "dexlab", programId: "DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N", description: "DexLab Swap/Pool." },
|
||||
{ label: "Aldrin (historical)", dexCode: "aldrin", programId: "AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Aldrin V2 (historical)", dexCode: "aldrin_v2", programId: "CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
@@ -49,7 +65,6 @@ const presets: Demo3Preset[] = [
|
||||
{ label: "Phoenix (historical)", dexCode: "phoenix", programId: "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Saber (historical)", dexCode: "saber", programId: "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "OpenBook V2 (historical)", dexCode: "openbook_v2", programId: "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "OpenBook (historical)", dexCode: "openbook", programId: "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Fox (historical)", dexCode: "fox", programId: "HyhpEq587ANShDdbx1mP4dTmDZC44CXWft29oYQXDb53", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Sanctum Infinity (historical)", dexCode: "sanctum_infinity", programId: "5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kx", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Saros (historical)", dexCode: "saros", programId: "SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
@@ -70,15 +85,8 @@ const presets: Demo3Preset[] = [
|
||||
{ label: "Invariant (historical)", dexCode: "invariant", programId: "HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Token Swap (historical)", dexCode: "token_swap", programId: "SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Helium Network (historical)", dexCode: "helium_network", programId: "treaf4wWBBty3fHdyBpo35Mz84M8k3heKXmjmi9vFt5", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Raydium Legacy V2 (historical)", dexCode: "raydium_legacy_v2", programId: "27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Raydium Legacy V3 (historical)", dexCode: "raydium_legacy_v3", programId: "7quYqsZdpWSZ3qgDextersDqoKjZy7aCgwHBBfRb7KPt", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Serum V3 (historical)", dexCode: "serum_v3", programId: "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Mango Private Pools (historical)", dexCode: "mango_private_pools", programId: "AtdP2iyfh6xBGwVZzHvY73E7uKKkZBTH2siHh3ZuEf1P", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Marinade Liquid Staking (historical)", dexCode: "marinade_liquid_staking", programId: "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Step Finance Pools (historical)", dexCode: "step_finance_pools", programId: "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Francium Yield Pools (historical)", dexCode: "francium_yield_pools", programId: "FC81tbGt6JWRXidaWYFXxGnTk4VgobhJHATvTRVMqgWj", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Cropper Legacy (historical)", dexCode: "cropper_legacy", programId: "CyZuD7RPDcrqCGbNvzrNVs1zpCQehqp7SuXB7rdFKSzo", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Dexlab Beta (historical)", dexCode: "dexlab_beta", programId: "9qvG1zP8ZzY1sTnExx7mkyxhW1063YHVYZxMYz2HkM4m", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Marinade Governance (historical)", dexCode: "marinade_governance", programId: "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Serum DAO (historical)", dexCode: "serum_dao", programId: "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Port Finance (historical)", dexCode: "port_finance", programId: "Port7uDYB3wk6GJAw4KT1WpTeMtSu9bTcChBHkX2LfR", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
@@ -88,10 +96,12 @@ const presets: Demo3Preset[] = [
|
||||
{ label: "Raydium Staking Early (historical)", dexCode: "raydium_staking_early", programId: "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Orca Aquafarm V1 (historical)", dexCode: "orca_aquafarm_v1", programId: "82yxjeMsvaURa4MbZZ7WZZHfobirZYkH1zF8fmeGtyaQ", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "Quarry Merge Mining (historical)", dexCode: "quarry_merge_mining", programId: "QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "SWAB Finance Beta (historical)", dexCode: "swab_finance_beta", programId: "SWABxNGyxEBVoNRGn6RvYBt5UqercSE5PBHuJeYXYHq", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "CRAFT Early (historical)", dexCode: "craft_early", programId: "CrAFTUv7zKXBaS5471aBiARBu6x7nP4rDzr8xwBewbr1", description: "Program id historique importé depuis entities.py; à vérifier par corpus." },
|
||||
{ label: "metaDAO", dexCode: "metadao", programId: "", description: "DEX à vérifier. Aucun program id n'est inventé." },
|
||||
{ label: "Printr", dexCode: "printr", programId: "", description: "DEX à vérifier. Aucun program id n'est inventé." },
|
||||
{ label: "Printr", dexCode: "printr", programId: "T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint", description: "Candidat Printr; à vérifier par corpus local." },
|
||||
{ label: "metaDAO — umbrella (manual)", dexCode: "metadao", programId: "", description: "Umbrella MetaDAO. Choisir de préférence une surface spécifique ci-dessous." },
|
||||
{ label: "metaDAO Launchpad v0.7.0", dexCode: "metadao_launchpad_v0_7_0", programId: "moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM", description: "Programme MetaDAO officiel candidat; à vérifier par corpus local." },
|
||||
{ label: "metaDAO Bid Wall v0.7.0", dexCode: "metadao_bid_wall_v0_7_0", programId: "WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx", description: "Programme MetaDAO officiel candidat; à vérifier par corpus local." },
|
||||
{ label: "metaDAO Futarchy v0.6.0", dexCode: "metadao_futarchy_v0_6_0", programId: "FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq", description: "Programme MetaDAO officiel candidat; à vérifier par corpus local." },
|
||||
{ label: "metaDAO AMM v0.5.0", dexCode: "metadao_amm_v0_5_0", programId: "AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ", description: "Programme MetaDAO officiel candidat; à vérifier par corpus local." },
|
||||
];
|
||||
|
||||
let lastResultJson = "";
|
||||
@@ -109,6 +119,16 @@ function valueOrNull(value: string): string | null {
|
||||
return trimmed === "" ? null : trimmed;
|
||||
}
|
||||
|
||||
function invalidBase58Characters(value: string): string[] {
|
||||
const invalid = new Set<string>();
|
||||
for (const character of value.trim()) {
|
||||
if (!/^[1-9A-HJ-NP-Za-km-z]$/.test(character)) {
|
||||
invalid.add(character);
|
||||
}
|
||||
}
|
||||
return Array.from(invalid);
|
||||
}
|
||||
|
||||
function isSolanaAddressLike(value: string): boolean {
|
||||
const trimmed = value.trim();
|
||||
if (trimmed.length < 32 || trimmed.length > 44) {
|
||||
@@ -161,6 +181,10 @@ function validateOnchainRequest(request: Demo3OnchainDexDiscoveryRequest): void
|
||||
validateOptionalSignature(request.beforeSignature, "Before signature");
|
||||
validateOptionalSignature(request.untilSignature, "Until signature");
|
||||
if (request.programId !== null && !isSolanaAddressLike(request.programId)) {
|
||||
const invalidCharacters = invalidBase58Characters(request.programId);
|
||||
if (invalidCharacters.length > 0) {
|
||||
throw new Error(`Program id filter must be a valid Solana base58 program id. Invalid character(s): ${invalidCharacters.join(", ")}.`);
|
||||
}
|
||||
throw new Error("Program id filter must be a valid Solana program id, or empty when using a preset that resolves it.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "kb-demo-app",
|
||||
"private": true,
|
||||
"version": "0.7.46",
|
||||
"version": "0.7.47",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -285,6 +285,239 @@ pub(crate) async fn demo3_search_local_dex_corpus(
|
||||
})
|
||||
}
|
||||
|
||||
/// Search request for the static upstream registry exposed through Demo3.
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/Demo3UpstreamRegistrySearchRequest.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Demo3UpstreamRegistrySearchRequest {
|
||||
/// Optional decoder-code filter.
|
||||
pub decoder_code: std::option::Option<std::string::String>,
|
||||
/// Optional program-id filter.
|
||||
pub program_id: std::option::Option<std::string::String>,
|
||||
/// Optional program-family filter.
|
||||
pub program_family: std::option::Option<std::string::String>,
|
||||
/// Optional surface-kind filter.
|
||||
pub surface_kind: std::option::Option<std::string::String>,
|
||||
/// Optional entry-kind filter.
|
||||
pub entry_kind: std::option::Option<std::string::String>,
|
||||
/// Optional proof-status filter.
|
||||
pub proof_status: std::option::Option<std::string::String>,
|
||||
/// Optional maximum number of entries to return.
|
||||
pub limit: std::option::Option<u32>,
|
||||
}
|
||||
|
||||
/// Payload returned by the Demo3 upstream registry command.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/Demo3UpstreamRegistryPayload.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Demo3UpstreamRegistryPayload {
|
||||
/// Pretty JSON representation of the registry result.
|
||||
pub result_json: std::string::String,
|
||||
/// Structured registry result.
|
||||
pub result: Demo3UpstreamRegistryResult,
|
||||
}
|
||||
|
||||
/// Structured upstream registry result exposed through Demo3.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/Demo3UpstreamRegistryResult.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Demo3UpstreamRegistryResult {
|
||||
/// Normalized request used by kb_lib.
|
||||
pub request: Demo3UpstreamRegistrySearchRequest,
|
||||
/// Registry summary.
|
||||
pub summary: Demo3UpstreamRegistrySummary,
|
||||
/// Matching entries.
|
||||
pub entries: std::vec::Vec<Demo3UpstreamRegistryEntry>,
|
||||
}
|
||||
|
||||
/// Summary of the upstream registry snapshot exposed through Demo3.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/Demo3UpstreamRegistrySummary.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Demo3UpstreamRegistrySummary {
|
||||
/// Total static registry entry count before filtering.
|
||||
#[ts(type = "number")]
|
||||
pub total_entry_count: usize,
|
||||
/// Returned entry count after filtering.
|
||||
#[ts(type = "number")]
|
||||
pub returned_entry_count: usize,
|
||||
/// Number of entries that have a program id.
|
||||
#[ts(type = "number")]
|
||||
pub entries_with_program_id_count: usize,
|
||||
/// Number of entries that have a discriminator.
|
||||
#[ts(type = "number")]
|
||||
pub entries_with_discriminator_count: usize,
|
||||
/// Number of program-level seed entries.
|
||||
#[ts(type = "number")]
|
||||
pub program_entry_count: usize,
|
||||
/// Number of instruction entries.
|
||||
#[ts(type = "number")]
|
||||
pub instruction_entry_count: usize,
|
||||
/// Number of event entries.
|
||||
#[ts(type = "number")]
|
||||
pub event_entry_count: usize,
|
||||
/// Number of account entries.
|
||||
#[ts(type = "number")]
|
||||
pub account_entry_count: usize,
|
||||
/// Number of entries still unverified from upstream Git or seed data.
|
||||
#[ts(type = "number")]
|
||||
pub upstream_git_unverified_count: usize,
|
||||
/// Number of entries mapped into decoders but not locally observed.
|
||||
#[ts(type = "number")]
|
||||
pub upstream_git_mapped_unverified_count: usize,
|
||||
/// Number of entries observed in the local corpus.
|
||||
#[ts(type = "number")]
|
||||
pub upstream_git_local_corpus_observed_count: usize,
|
||||
/// Number of entries materialized in local business tables.
|
||||
#[ts(type = "number")]
|
||||
pub upstream_git_local_corpus_materialized_count: usize,
|
||||
/// Number of layout entries still unverified locally.
|
||||
#[ts(type = "number")]
|
||||
pub upstream_git_layout_unverified_count: usize,
|
||||
}
|
||||
|
||||
/// One upstream registry entry exposed through Demo3.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/Demo3UpstreamRegistryEntry.ts")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Demo3UpstreamRegistryEntry {
|
||||
/// Repository name or bootstrap locator that produced the entry.
|
||||
pub source_repo: std::option::Option<std::string::String>,
|
||||
/// Repository-relative path or bootstrap path that produced the entry.
|
||||
pub source_path: std::option::Option<std::string::String>,
|
||||
/// Stable decoder code used by the registry.
|
||||
pub decoder_code: std::string::String,
|
||||
/// Optional Solana program id when already known by the source entry.
|
||||
pub program_id: std::option::Option<std::string::String>,
|
||||
/// Program family used to group related programs.
|
||||
pub program_family: std::string::String,
|
||||
/// Surface kind such as AMM, CLMM, launch, aggregator or core Solana.
|
||||
pub surface_kind: std::string::String,
|
||||
/// Entry kind: instruction, event, account or program.
|
||||
pub entry_kind: std::string::String,
|
||||
/// Source-level entry name.
|
||||
pub entry_name: std::string::String,
|
||||
/// Optional discriminator bytes encoded as lowercase hexadecimal.
|
||||
pub discriminator_hex: std::option::Option<std::string::String>,
|
||||
/// Optional discriminator byte length.
|
||||
pub discriminator_len: std::option::Option<u16>,
|
||||
/// Current proof status.
|
||||
pub proof_status: std::string::String,
|
||||
/// Notes that preserve uncertainty and validation requirements.
|
||||
pub notes: std::string::String,
|
||||
}
|
||||
|
||||
/// Searches the static upstream registry from Demo3.
|
||||
#[tauri::command]
|
||||
pub(crate) fn demo3_search_upstream_registry(
|
||||
request: Demo3UpstreamRegistrySearchRequest,
|
||||
) -> Result<Demo3UpstreamRegistryPayload, std::string::String> {
|
||||
let service = kb_lib::UpstreamRegistryService::new();
|
||||
let lib_request = to_lib_upstream_registry_request(&request);
|
||||
let lib_result = service.search(&lib_request);
|
||||
let ui_result = from_lib_upstream_registry_result(lib_result);
|
||||
let result_json_result = serde_json::to_string_pretty(&ui_result);
|
||||
let result_json = match result_json_result {
|
||||
Ok(result_json) => result_json,
|
||||
Err(error) => {
|
||||
return Err(format!("cannot serialize upstream registry result: {}", error));
|
||||
},
|
||||
};
|
||||
return Ok(Demo3UpstreamRegistryPayload {
|
||||
result_json,
|
||||
result: ui_result,
|
||||
});
|
||||
}
|
||||
|
||||
fn to_lib_upstream_registry_request(
|
||||
request: &Demo3UpstreamRegistrySearchRequest,
|
||||
) -> kb_lib::UpstreamRegistrySearchRequestDto {
|
||||
return kb_lib::UpstreamRegistrySearchRequestDto {
|
||||
decoder_code: normalize_optional_text(request.decoder_code.clone()),
|
||||
program_id: normalize_optional_text(request.program_id.clone()),
|
||||
program_family: normalize_optional_text(request.program_family.clone()),
|
||||
surface_kind: normalize_optional_text(request.surface_kind.clone()),
|
||||
entry_kind: normalize_optional_text(request.entry_kind.clone()),
|
||||
proof_status: normalize_optional_text(request.proof_status.clone()),
|
||||
limit: match request.limit {
|
||||
Some(limit) => Some(limit as usize),
|
||||
None => None,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn from_lib_upstream_registry_result(
|
||||
result: kb_lib::UpstreamRegistrySearchResultDto,
|
||||
) -> Demo3UpstreamRegistryResult {
|
||||
let mut entries = std::vec::Vec::new();
|
||||
for entry in result.entries {
|
||||
entries.push(from_lib_upstream_registry_entry(entry));
|
||||
}
|
||||
return Demo3UpstreamRegistryResult {
|
||||
request: from_lib_upstream_registry_request(result.request),
|
||||
summary: from_lib_upstream_registry_summary(result.summary),
|
||||
entries,
|
||||
};
|
||||
}
|
||||
|
||||
fn from_lib_upstream_registry_request(
|
||||
request: kb_lib::UpstreamRegistrySearchRequestDto,
|
||||
) -> Demo3UpstreamRegistrySearchRequest {
|
||||
return Demo3UpstreamRegistrySearchRequest {
|
||||
decoder_code: request.decoder_code,
|
||||
program_id: request.program_id,
|
||||
program_family: request.program_family,
|
||||
surface_kind: request.surface_kind,
|
||||
entry_kind: request.entry_kind,
|
||||
proof_status: request.proof_status,
|
||||
limit: match request.limit {
|
||||
Some(limit) => Some(limit as u32),
|
||||
None => None,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn from_lib_upstream_registry_summary(
|
||||
summary: kb_lib::UpstreamRegistrySummaryDto,
|
||||
) -> Demo3UpstreamRegistrySummary {
|
||||
return Demo3UpstreamRegistrySummary {
|
||||
total_entry_count: summary.total_entry_count,
|
||||
returned_entry_count: summary.returned_entry_count,
|
||||
entries_with_program_id_count: summary.entries_with_program_id_count,
|
||||
entries_with_discriminator_count: summary.entries_with_discriminator_count,
|
||||
program_entry_count: summary.program_entry_count,
|
||||
instruction_entry_count: summary.instruction_entry_count,
|
||||
event_entry_count: summary.event_entry_count,
|
||||
account_entry_count: summary.account_entry_count,
|
||||
upstream_git_unverified_count: summary.upstream_git_unverified_count,
|
||||
upstream_git_mapped_unverified_count: summary.upstream_git_mapped_unverified_count,
|
||||
upstream_git_local_corpus_observed_count: summary
|
||||
.upstream_git_local_corpus_observed_count,
|
||||
upstream_git_local_corpus_materialized_count: summary
|
||||
.upstream_git_local_corpus_materialized_count,
|
||||
upstream_git_layout_unverified_count: summary.upstream_git_layout_unverified_count,
|
||||
};
|
||||
}
|
||||
|
||||
fn from_lib_upstream_registry_entry(
|
||||
entry: kb_lib::UpstreamRegistryEntryDto,
|
||||
) -> Demo3UpstreamRegistryEntry {
|
||||
return Demo3UpstreamRegistryEntry {
|
||||
source_repo: entry.source_repo,
|
||||
source_path: entry.source_path,
|
||||
decoder_code: entry.decoder_code,
|
||||
program_id: entry.program_id,
|
||||
program_family: entry.program_family,
|
||||
surface_kind: entry.surface_kind,
|
||||
entry_kind: entry.entry_kind,
|
||||
entry_name: entry.entry_name,
|
||||
discriminator_hex: entry.discriminator_hex,
|
||||
discriminator_len: entry.discriminator_len,
|
||||
proof_status: entry.proof_status,
|
||||
notes: entry.notes,
|
||||
};
|
||||
}
|
||||
|
||||
fn to_lib_search_request(
|
||||
request: &Demo3LocalDexCorpusSearchRequest,
|
||||
) -> kb_lib::LocalDexCorpusSearchRequestDto {
|
||||
|
||||
@@ -125,6 +125,7 @@ pub async fn run() -> Result<(), kb_lib::Error> {
|
||||
stop_ws_clients,
|
||||
crate::demo3::open_demo3_window,
|
||||
crate::demo3::demo3_search_local_dex_corpus,
|
||||
crate::demo3::demo3_search_upstream_registry,
|
||||
crate::demo3::demo3_discover_onchain_dex_pairs,
|
||||
crate::demo3old::open_demo3old_window,
|
||||
crate::demo3old::demo3old_search_local_dex_corpus,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "kb-demo-app",
|
||||
"version": "0.7.46",
|
||||
"version": "0.7.47",
|
||||
"identifier": "com.sasedev.kb-demo-app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
@@ -18,6 +18,9 @@ pub const ASSOCIATED_TOKEN_PROGRAM_ID: &str = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25e
|
||||
/// @see solana_sdk_ids::address_lookup_table::ID
|
||||
pub const ADDRESS_LOOKUP_TABLE_PROGRAM_ID: &str = "AddressLookupTab1e1111111111111111111111111";
|
||||
|
||||
/// SPL Memo program id. ("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr").
|
||||
pub const MEMO_PROGRAM_ID: &str = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
||||
|
||||
/// BPF Loader program identifier. ("BPFLoader1111111111111111111111111111111111").
|
||||
/// @see solana_sdk_ids::bpf_loader_deprecated::ID
|
||||
pub const BPF_LOADER_DEPRECATED_PROGRAM_ID: &str = "BPFLoader1111111111111111111111111111111111";
|
||||
@@ -164,6 +167,57 @@ pub const DEXLAB_PROGRAM_ID: &str = "DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6
|
||||
/// FluxBeam program id. ("FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X").
|
||||
pub const FLUXBEAM_PROGRAM_ID: &str = "FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X";
|
||||
|
||||
/// GooseFX v1 program id from Vybe supported DEX/AMM documentation.
|
||||
pub const GOOSEFX_V1_PROGRAM_ID: &str = "GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT";
|
||||
|
||||
/// Obric v2 program id from Vybe supported DEX/AMM documentation.
|
||||
pub const OBRIC_V2_PROGRAM_ID: &str = "obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y";
|
||||
|
||||
/// Ondo Global Market program id from Vybe supported DEX/AMM documentation.
|
||||
pub const ONDO_GLOBAL_MARKET_PROGRAM_ID: &str = "XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm";
|
||||
|
||||
/// Scorch program id from Vybe supported DEX/AMM documentation.
|
||||
pub const SCORCH_PROGRAM_ID: &str = "SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn";
|
||||
|
||||
/// ZeroFi program id from Vybe supported DEX/AMM documentation.
|
||||
pub const ZEROFI_PROGRAM_ID: &str = "ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY";
|
||||
|
||||
/// Manifest CLOB program id from Vybe supported DEX/AMM documentation.
|
||||
pub const MANIFEST_CLOB_PROGRAM_ID: &str = "MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms";
|
||||
|
||||
/// AlphaQ program id from Vybe supported DEX/AMM documentation.
|
||||
pub const ALPHAQ_PROGRAM_ID: &str = "ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA";
|
||||
|
||||
/// Goonfi program id from Vybe supported DEX/AMM documentation.
|
||||
pub const GOONFI_PROGRAM_ID: &str = "goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j";
|
||||
|
||||
/// Goonfi v2 program id from Vybe supported DEX/AMM documentation.
|
||||
pub const GOONFI_V2_PROGRAM_ID: &str = "goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE";
|
||||
|
||||
/// Byreal program id from Vybe supported DEX/AMM documentation.
|
||||
pub const BYREAL_PROGRAM_ID: &str = "REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2";
|
||||
|
||||
/// BisonFi program id from Vybe supported DEX/AMM documentation.
|
||||
pub const BISONFI_PROGRAM_ID: &str = "BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi";
|
||||
|
||||
/// FusionAMM program id from Vybe supported DEX/AMM documentation.
|
||||
pub const FUSIONAMM_PROGRAM_ID: &str = "fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9";
|
||||
|
||||
/// Woofi program id from Vybe supported DEX/AMM documentation.
|
||||
pub const WOOFI_PROGRAM_ID: &str = "WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb";
|
||||
|
||||
/// Aquifer program id from Vybe supported DEX/AMM documentation.
|
||||
pub const AQUIFER_PROGRAM_ID: &str = "AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45";
|
||||
|
||||
/// Humidifi program id from Vybe supported DEX/AMM documentation.
|
||||
pub const HUMIDIFI_PROGRAM_ID: &str = "9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp";
|
||||
|
||||
/// SolFi v2 program id from Vybe supported DEX/AMM documentation.
|
||||
pub const SOLFI_V2_PROGRAM_ID: &str = "SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF";
|
||||
|
||||
/// Gavel program id extracted from upstream Git decoder source.
|
||||
pub const GAVEL_PROGRAM_ID: &str = "srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi";
|
||||
|
||||
/// Meteora DAMM v1 program id. ("Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB").
|
||||
pub const METEORA_DAMM_V1_PROGRAM_ID: &str = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB";
|
||||
|
||||
@@ -178,32 +232,17 @@ pub const METEORA_DBC_PROGRAM_ID: &str = "dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4Du
|
||||
/// DLMM = Dynamic Liquidity Market Maker.
|
||||
pub const METEORA_DLMM_PROGRAM_ID: &str = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
|
||||
|
||||
/// MetaDAO META active token mint identifier from MetaDAO documentation.
|
||||
pub const METADAO_META_MINT_ID: &str = "METAwkXcqyXKy1AtsSgJ8JiUHwGCafnZL38n3vYmeta";
|
||||
|
||||
/// MetaDAO METAC legacy token mint identifier from MetaDAO documentation.
|
||||
pub const METADAO_METAC_LEGACY_MINT_ID: &str = "METADDFL6wWMWEoKTFJwcThTbUmtarRJZjRpzUvkxhr";
|
||||
|
||||
/// MetaDAO-linked P2P token mint candidate observed on Solscan.
|
||||
///
|
||||
/// This is a token mint, not a DEX program id. It is exposed for discovery only.
|
||||
pub const METADAO_P2P_MINT_ID: &str = "P2PXup1ZvMpCDkJn3PQxtBYgxeCSfH39SFeurGSmeta";
|
||||
|
||||
/// MetaDAO Launchpad v0.7.0 program id from MetaDAO documentation and Solscan.
|
||||
pub const METADAO_LAUNCHPAD_V0_7_0_PROGRAM_ID: &str =
|
||||
"moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM";
|
||||
pub const METADAO_LAUNCHPAD_V0_7_0_PROGRAM_ID: &str = "moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM";
|
||||
|
||||
/// MetaDAO Bid Wall v0.7.0 program id from MetaDAO documentation.
|
||||
pub const METADAO_BID_WALL_V0_7_0_PROGRAM_ID: &str =
|
||||
"WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx";
|
||||
pub const METADAO_BID_WALL_V0_7_0_PROGRAM_ID: &str = "WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx";
|
||||
|
||||
/// MetaDAO Futarchy v0.6.0 program id from MetaDAO documentation.
|
||||
pub const METADAO_FUTARCHY_V0_6_0_PROGRAM_ID: &str =
|
||||
"FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq";
|
||||
pub const METADAO_FUTARCHY_V0_6_0_PROGRAM_ID: &str = "FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq";
|
||||
|
||||
/// MetaDAO AMM v0.5.0 program id from MetaDAO documentation.
|
||||
pub const METADAO_AMM_V0_5_0_PROGRAM_ID: &str =
|
||||
"AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ";
|
||||
pub const METADAO_AMM_V0_5_0_PROGRAM_ID: &str = "AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ";
|
||||
|
||||
/// Printr program id candidate observed on Solscan.
|
||||
///
|
||||
@@ -224,6 +263,9 @@ pub const PUMP_FUN_PROGRAM_ID: &str = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF
|
||||
/// PumpSwap / PumpAMM program id. ("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA").
|
||||
pub const PUMP_SWAP_PROGRAM_ID: &str = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
|
||||
|
||||
/// Pump Fees program id extracted from upstream Git decoder source.
|
||||
pub const PUMP_FEES_PROGRAM_ID: &str = "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ";
|
||||
|
||||
/// Raydium AmmV4 program id. ("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8").
|
||||
pub const RAYDIUM_AMM_V4_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
|
||||
|
||||
@@ -233,7 +275,7 @@ pub const RAYDIUM_CLMM_PROGRAM_ID: &str = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7gr
|
||||
/// Raydium CPMM mainnet program id. ("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C").
|
||||
pub const RAYDIUM_CPMM_PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
|
||||
|
||||
/// Raydium LaunchLab program id. ("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj").
|
||||
/// Raydium LaunchLab / Launchpad program id. ("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj").
|
||||
pub const RAYDIUM_LAUNCHLAB_PROGRAM_ID: &str = "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj";
|
||||
|
||||
/// Raydium AMM routing program id. ("routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS").
|
||||
@@ -242,6 +284,132 @@ pub const RAYDIUM_AMM_ROUTING_PROGRAM_ID: &str = "routeUGWgWzqBWFcrCfv8tritsqukc
|
||||
/// Raydium Stable Swap AMM program id, deprecated. ("5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h").
|
||||
pub const RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID: &str = "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h";
|
||||
|
||||
/// Bonkswap program id extracted from upstream Git decoder source.
|
||||
pub const BONKSWAP_PROGRAM_ID: &str = "BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p";
|
||||
|
||||
/// Boop program id extracted from upstream Git decoder source.
|
||||
pub const BOOP_PROGRAM_ID: &str = "boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4";
|
||||
|
||||
/// DFlow Aggregator v4 program id extracted from upstream Git decoder source.
|
||||
pub const DFLOW_AGGREGATOR_V4_PROGRAM_ID: &str = "DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH";
|
||||
|
||||
/// Drift v2 program id extracted from upstream Git decoder source.
|
||||
pub const DRIFT_V2_PROGRAM_ID: &str = "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH";
|
||||
|
||||
/// Heaven program id extracted from upstream Git decoder source.
|
||||
pub const HEAVEN_PROGRAM_ID: &str = "HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o";
|
||||
|
||||
/// Jupiter Swap program id extracted from upstream Git decoder source.
|
||||
pub const JUPITER_SWAP_PROGRAM_ID: &str = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
|
||||
|
||||
/// Jupiter DCA program id extracted from upstream Git decoder source.
|
||||
pub const JUPITER_DCA_PROGRAM_ID: &str = "DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M";
|
||||
|
||||
/// Jupiter Lend program id extracted from upstream Git decoder source.
|
||||
pub const JUPITER_LEND_PROGRAM_ID: &str = "jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC";
|
||||
|
||||
/// Jupiter Limit Order program id extracted from upstream Git decoder source.
|
||||
pub const JUPITER_LIMIT_ORDER_PROGRAM_ID: &str = "jupoNjAxXgZ4rjzxzPMP4oxduvQsQtZzyknqvzYNrNu";
|
||||
|
||||
/// Jupiter Limit Order 2 program id extracted from upstream Git decoder source.
|
||||
pub const JUPITER_LIMIT_ORDER_2_PROGRAM_ID: &str = "j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X";
|
||||
|
||||
/// Jupiter Perpetuals program id extracted from upstream Git decoder source.
|
||||
pub const JUPITER_PERPETUALS_PROGRAM_ID: &str = "PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu";
|
||||
|
||||
/// Kamino Farms program id extracted from upstream Git decoder source.
|
||||
pub const KAMINO_FARMS_PROGRAM_ID: &str = "FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr";
|
||||
|
||||
/// Kamino Lending program id extracted from upstream Git decoder source.
|
||||
pub const KAMINO_LENDING_PROGRAM_ID: &str = "KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD";
|
||||
|
||||
/// Kamino Limit Order program id extracted from upstream Git decoder source.
|
||||
pub const KAMINO_LIMIT_ORDER_PROGRAM_ID: &str = "LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF";
|
||||
|
||||
/// Kamino Vault program id extracted from upstream Git decoder source.
|
||||
pub const KAMINO_VAULT_PROGRAM_ID: &str = "kvauTFR8qm1dhniz6pYuBZkuene3Hfrs1VQhVRgCNrr";
|
||||
|
||||
/// Lifinity AMM v2 program id extracted from upstream Git decoder source.
|
||||
pub const LIFINITY_AMM_V2_PROGRAM_ID: &str = "2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c";
|
||||
|
||||
/// Marginfi v2 program id extracted from upstream Git decoder source.
|
||||
pub const MARGINFI_V2_PROGRAM_ID: &str = "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA";
|
||||
|
||||
/// Marinade Finance program id extracted from upstream Git decoder source.
|
||||
pub const MARINADE_FINANCE_PROGRAM_ID: &str = "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD";
|
||||
|
||||
/// Meteora Vault program id extracted from upstream Git decoder source.
|
||||
pub const METEORA_VAULT_PROGRAM_ID: &str = "24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi";
|
||||
|
||||
/// Moonshot program id extracted from upstream Git decoder source.
|
||||
pub const MOONSHOT_PROGRAM_ID: &str = "MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG";
|
||||
|
||||
/// OKX DEX program id extracted from upstream Git decoder source.
|
||||
pub const OKX_DEX_PROGRAM_ID: &str = "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma";
|
||||
|
||||
/// Onchain Labs DEX v2 program id extracted from upstream Git decoder source.
|
||||
pub const ONCHAIN_LABS_DEX_V2_PROGRAM_ID: &str = "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u";
|
||||
|
||||
/// OpenBook v2 program id extracted from upstream Git decoder source.
|
||||
pub const OPENBOOK_V2_PROGRAM_ID: &str = "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb";
|
||||
|
||||
/// Pancake Swap program id extracted from upstream Git decoder source.
|
||||
pub const PANCAKE_SWAP_PROGRAM_ID: &str = "HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq";
|
||||
|
||||
/// Phoenix v1 program id extracted from upstream Git decoder source.
|
||||
pub const PHOENIX_V1_PROGRAM_ID: &str = "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY";
|
||||
|
||||
/// Raydium Liquidity Locking program id extracted from upstream Git decoder source.
|
||||
pub const RAYDIUM_LIQUIDITY_LOCKING_PROGRAM_ID: &str =
|
||||
"LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE";
|
||||
|
||||
/// Sharky program id extracted from upstream Git decoder source.
|
||||
pub const SHARKY_PROGRAM_ID: &str = "SHARKobtfF1bHhxD2eqftjHBdVSCbKo9JtgK71FhELP";
|
||||
|
||||
/// Solayer Restaking program id extracted from upstream Git decoder source.
|
||||
pub const SOLAYER_RESTAKING_PROGRAM_ID: &str = "sSo1iU21jBrU9VaJ8PJib1MtorefUV4fzC9GURa2KNn";
|
||||
|
||||
/// Stabble stable-swap program id extracted from upstream Git decoder source.
|
||||
pub const STABBLE_STABLE_SWAP_PROGRAM_ID: &str = "swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ";
|
||||
|
||||
/// Stabble weighted-swap program id extracted from upstream Git decoder source.
|
||||
pub const STABBLE_WEIGHTED_SWAP_PROGRAM_ID: &str = "swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW";
|
||||
|
||||
/// Swig program id extracted from upstream Git decoder source.
|
||||
pub const SWIG_PROGRAM_ID: &str = "swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB";
|
||||
|
||||
/// Vertigo program id extracted from upstream Git decoder source.
|
||||
pub const VERTIGO_PROGRAM_ID: &str = "vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ";
|
||||
|
||||
/// Virtuals program id extracted from upstream Git decoder source.
|
||||
pub const VIRTUALS_PROGRAM_ID: &str = "5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki";
|
||||
|
||||
/// Wavebreak program id extracted from upstream Git decoder source.
|
||||
pub const WAVEBREAK_PROGRAM_ID: &str = "waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF";
|
||||
|
||||
/// Zeta program id extracted from upstream Git decoder source.
|
||||
pub const ZETA_PROGRAM_ID: &str = "ZETAxsqBRek56DhiGXrn75yj2NHU3aYUnxvHXpkf3aD";
|
||||
|
||||
/// Circle Message Transmitter v2 program id extracted from upstream Git decoder source.
|
||||
pub const CIRCLE_MESSAGE_TRANSMITTER_V2_PROGRAM_ID: &str =
|
||||
"CCTPV2Sm4AdWt5296sk4P66VBZ7bEhcARwFaaS9YPbeC";
|
||||
|
||||
/// Circle Token Messenger v2 program id extracted from upstream Git decoder source.
|
||||
pub const CIRCLE_TOKEN_MESSENGER_V2_PROGRAM_ID: &str =
|
||||
"CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe";
|
||||
|
||||
/// MPL Token Metadata program id extracted from upstream Git decoder source.
|
||||
pub const MPL_TOKEN_METADATA_PROGRAM_ID: &str = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
||||
|
||||
/// MPL Core program id extracted from upstream Git decoder source.
|
||||
pub const MPL_CORE_PROGRAM_ID: &str = "CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d";
|
||||
|
||||
/// Bubblegum program id extracted from upstream Git decoder source.
|
||||
pub const BUBBLEGUM_PROGRAM_ID: &str = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY";
|
||||
|
||||
/// Solana Name Service program id extracted from upstream Git decoder source.
|
||||
pub const NAME_SERVICE_PROGRAM_ID: &str = "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX";
|
||||
|
||||
/// Known Solana arbitrage/sandwich bot program id observed in local corpus.
|
||||
///
|
||||
/// This is not treated as a DEX program. It is used only to tag protocol
|
||||
|
||||
@@ -8,7 +8,9 @@ mod meteora_damm_v1;
|
||||
mod meteora_damm_v2;
|
||||
mod meteora_dbc;
|
||||
mod meteora_dlmm;
|
||||
mod openbook_v2;
|
||||
mod orca_whirlpools;
|
||||
mod phoenix_v1;
|
||||
mod pump_fun;
|
||||
mod pump_swap;
|
||||
mod raydium_amm_v4;
|
||||
@@ -47,10 +49,16 @@ pub use meteora_dlmm::MeteoraDlmmLiquidityDecoded;
|
||||
pub use meteora_dlmm::MeteoraDlmmPoolLifecycleDecoded;
|
||||
pub use meteora_dlmm::MeteoraDlmmRewardDecoded;
|
||||
pub use meteora_dlmm::MeteoraDlmmSwapDecoded;
|
||||
pub use openbook_v2::OpenBookV2AuditDecoded;
|
||||
pub use openbook_v2::OpenBookV2DecodedEvent;
|
||||
pub use openbook_v2::OpenBookV2Decoder;
|
||||
pub use orca_whirlpools::OrcaWhirlpoolsCreatePoolDecoded;
|
||||
pub use orca_whirlpools::OrcaWhirlpoolsDecodedEvent;
|
||||
pub use orca_whirlpools::OrcaWhirlpoolsDecoder;
|
||||
pub use orca_whirlpools::OrcaWhirlpoolsSwapDecoded;
|
||||
pub use phoenix_v1::PhoenixV1AuditDecoded;
|
||||
pub use phoenix_v1::PhoenixV1DecodedEvent;
|
||||
pub use phoenix_v1::PhoenixV1Decoder;
|
||||
pub use pump_fun::PumpFunCreateV2TokenDecoded;
|
||||
pub use pump_fun::PumpFunDecodedEvent;
|
||||
pub use pump_fun::PumpFunDecoder;
|
||||
|
||||
1591
kb_lib/src/dex/openbook_v2.rs
Normal file
1591
kb_lib/src/dex/openbook_v2.rs
Normal file
File diff suppressed because it is too large
Load Diff
1325
kb_lib/src/dex/phoenix_v1.rs
Normal file
1325
kb_lib/src/dex/phoenix_v1.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -124,7 +124,6 @@ mod tests {
|
||||
fn planned_launch_surfaces_are_present_but_disabled() {
|
||||
let codes = [
|
||||
"raydium_launchlab",
|
||||
"raydium_launchpad",
|
||||
"letsbonk",
|
||||
"boop_fun",
|
||||
"moonshot",
|
||||
|
||||
@@ -20,6 +20,8 @@ pub struct DexDecodeService {
|
||||
meteora_damm_v2_decoder: crate::MeteoraDammV2Decoder,
|
||||
fluxbeam_decoder: crate::FluxbeamDecoder,
|
||||
dexlab_decoder: crate::DexlabDecoder,
|
||||
openbook_v2_decoder: crate::OpenBookV2Decoder,
|
||||
phoenix_v1_decoder: crate::PhoenixV1Decoder,
|
||||
}
|
||||
|
||||
impl DexDecodeService {
|
||||
@@ -40,6 +42,8 @@ impl DexDecodeService {
|
||||
meteora_damm_v2_decoder: crate::MeteoraDammV2Decoder::new(),
|
||||
fluxbeam_decoder: crate::FluxbeamDecoder::new(),
|
||||
dexlab_decoder: crate::DexlabDecoder::new(),
|
||||
openbook_v2_decoder: crate::OpenBookV2Decoder::new(),
|
||||
phoenix_v1_decoder: crate::PhoenixV1Decoder::new(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -163,6 +167,36 @@ impl DexDecodeService {
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
}
|
||||
let append_result = append_persisted_events_result(
|
||||
&mut persisted,
|
||||
self.decode_and_persist_openbook_v2_audit_events(&transaction, &instructions)
|
||||
.await,
|
||||
);
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
}
|
||||
let append_result = append_persisted_events_result(
|
||||
&mut persisted,
|
||||
self.decode_and_persist_phoenix_v1_audit_events(&transaction, &instructions)
|
||||
.await,
|
||||
);
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
let decoded_instruction_ids = decoded_instruction_ids_from_persisted_events(&persisted);
|
||||
let append_result = append_persisted_events_result(
|
||||
&mut persisted,
|
||||
self.decode_and_persist_upstream_registry_matches(
|
||||
&transaction,
|
||||
&instructions,
|
||||
&decoded_instruction_ids,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
if let Err(error) = append_result {
|
||||
return Err(error);
|
||||
}
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
@@ -218,9 +252,46 @@ impl DexDecodeService {
|
||||
if let Err(error) = cleanup_result {
|
||||
return Err(error);
|
||||
}
|
||||
let cleanup_result = self
|
||||
.delete_replaced_upstream_registry_match(
|
||||
transaction_id,
|
||||
instruction_id,
|
||||
protocol_name,
|
||||
event_kind,
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = cleanup_result {
|
||||
return Err(error);
|
||||
}
|
||||
return Ok(materialized);
|
||||
}
|
||||
|
||||
async fn delete_replaced_upstream_registry_match(
|
||||
&self,
|
||||
transaction_id: i64,
|
||||
instruction_id: i64,
|
||||
protocol_name: &str,
|
||||
event_kind: &str,
|
||||
) -> Result<(), crate::Error> {
|
||||
if protocol_name == crate::UPSTREAM_REGISTRY_PROTOCOL_NAME {
|
||||
return Ok(());
|
||||
}
|
||||
if event_kind == crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND {
|
||||
return Ok(());
|
||||
}
|
||||
let delete_result = crate::query_dex_decoded_events_delete_by_key(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
Some(instruction_id),
|
||||
crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND,
|
||||
)
|
||||
.await;
|
||||
match delete_result {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_replaced_instruction_audit(
|
||||
&self,
|
||||
transaction_id: i64,
|
||||
@@ -248,6 +319,92 @@ impl DexDecodeService {
|
||||
}
|
||||
}
|
||||
|
||||
async fn decode_and_persist_upstream_registry_matches(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
instructions: &[crate::ChainInstructionDto],
|
||||
already_decoded_instruction_ids: &std::collections::HashSet<i64>,
|
||||
) -> Result<std::vec::Vec<crate::DexDecodedEventDto>, crate::Error> {
|
||||
let transaction_id = match transaction.id {
|
||||
Some(transaction_id) => transaction_id,
|
||||
None => {
|
||||
return Err(crate::Error::InvalidState(format!(
|
||||
"transaction '{}' has no internal id",
|
||||
transaction.signature
|
||||
)));
|
||||
},
|
||||
};
|
||||
let decoded_events_result = crate::query_dex_decoded_events_list_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
)
|
||||
.await;
|
||||
let decoded_events = match decoded_events_result {
|
||||
Ok(decoded_events) => decoded_events,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let mut decoded_instruction_ids = already_decoded_instruction_ids.clone();
|
||||
for decoded_event in &decoded_events {
|
||||
let instruction_id = match decoded_event.instruction_id {
|
||||
Some(instruction_id) => instruction_id,
|
||||
None => continue,
|
||||
};
|
||||
decoded_instruction_ids.insert(instruction_id);
|
||||
}
|
||||
let mut persisted = std::vec::Vec::new();
|
||||
for instruction in instructions {
|
||||
let instruction_id = match instruction.id {
|
||||
Some(instruction_id) => instruction_id,
|
||||
None => continue,
|
||||
};
|
||||
if decoded_instruction_ids.contains(&instruction_id) {
|
||||
continue;
|
||||
}
|
||||
let program_id = match instruction.program_id.as_ref() {
|
||||
Some(program_id) => program_id,
|
||||
None => continue,
|
||||
};
|
||||
let data_base58 = parse_instruction_data_base58(instruction.data_json.as_deref());
|
||||
let registry_match =
|
||||
crate::upstream_registry_match::upstream_registry_match_instruction_data(
|
||||
program_id.as_str(),
|
||||
data_base58.as_deref(),
|
||||
);
|
||||
let registry_match = match registry_match {
|
||||
Some(registry_match) => registry_match,
|
||||
None => continue,
|
||||
};
|
||||
let payload = build_upstream_registry_instruction_match_payload(
|
||||
transaction,
|
||||
instruction,
|
||||
®istry_match,
|
||||
data_base58.as_deref(),
|
||||
);
|
||||
let persist_result = self
|
||||
.materialize_named_dex_event(
|
||||
transaction,
|
||||
transaction_id,
|
||||
instruction_id,
|
||||
crate::UPSTREAM_REGISTRY_PROTOCOL_NAME,
|
||||
program_id.clone(),
|
||||
crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
payload,
|
||||
)
|
||||
.await;
|
||||
let persisted_event = match persist_result {
|
||||
Ok(persisted_event) => persisted_event,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
persisted.push(persisted_event);
|
||||
}
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
async fn persist_dexlab_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
@@ -1480,6 +1637,104 @@ impl DexDecodeService {
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
async fn persist_openbook_v2_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
decoded_event: &crate::OpenBookV2DecodedEvent,
|
||||
) -> Result<crate::DexDecodedEventDto, crate::Error> {
|
||||
match decoded_event {
|
||||
crate::OpenBookV2DecodedEvent::Audit(event) => {
|
||||
return self
|
||||
.materialize_named_dex_event(
|
||||
transaction,
|
||||
event.transaction_id,
|
||||
event.instruction_id,
|
||||
"openbook_v2",
|
||||
event.program_id.clone(),
|
||||
event.event_kind.as_str(),
|
||||
None,
|
||||
event.market_account.clone(),
|
||||
event.token_a_mint.clone(),
|
||||
event.token_b_mint.clone(),
|
||||
None,
|
||||
event.payload_json.clone(),
|
||||
)
|
||||
.await;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn decode_and_persist_openbook_v2_audit_events(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
instructions: &[crate::ChainInstructionDto],
|
||||
) -> Result<std::vec::Vec<crate::DexDecodedEventDto>, crate::Error> {
|
||||
let decoded_result = self.openbook_v2_decoder.decode_transaction(transaction, instructions);
|
||||
let decoded_events = match decoded_result {
|
||||
Ok(decoded_events) => decoded_events,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let mut persisted = std::vec::Vec::new();
|
||||
for decoded_event in &decoded_events {
|
||||
let persist_result = self.persist_openbook_v2_event(transaction, decoded_event).await;
|
||||
let persisted_event = match persist_result {
|
||||
Ok(persisted_event) => persisted_event,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
persisted.push(persisted_event);
|
||||
}
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
async fn persist_phoenix_v1_event(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
decoded_event: &crate::PhoenixV1DecodedEvent,
|
||||
) -> Result<crate::DexDecodedEventDto, crate::Error> {
|
||||
match decoded_event {
|
||||
crate::PhoenixV1DecodedEvent::Audit(event) => {
|
||||
return self
|
||||
.materialize_named_dex_event(
|
||||
transaction,
|
||||
event.transaction_id,
|
||||
event.instruction_id,
|
||||
"phoenix_v1",
|
||||
event.program_id.clone(),
|
||||
event.event_kind.as_str(),
|
||||
None,
|
||||
event.market_account.clone(),
|
||||
event.token_a_mint.clone(),
|
||||
event.token_b_mint.clone(),
|
||||
None,
|
||||
event.payload_json.clone(),
|
||||
)
|
||||
.await;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn decode_and_persist_phoenix_v1_audit_events(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
instructions: &[crate::ChainInstructionDto],
|
||||
) -> Result<std::vec::Vec<crate::DexDecodedEventDto>, crate::Error> {
|
||||
let decoded_result = self.phoenix_v1_decoder.decode_transaction(transaction, instructions);
|
||||
let decoded_events = match decoded_result {
|
||||
Ok(decoded_events) => decoded_events,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let mut persisted = std::vec::Vec::new();
|
||||
for decoded_event in &decoded_events {
|
||||
let persist_result = self.persist_phoenix_v1_event(transaction, decoded_event).await;
|
||||
let persisted_event = match persist_result {
|
||||
Ok(persisted_event) => persisted_event,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
persisted.push(persisted_event);
|
||||
}
|
||||
return Ok(persisted);
|
||||
}
|
||||
|
||||
async fn decode_and_persist_fluxbeam_events(
|
||||
&self,
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
@@ -1964,7 +2219,7 @@ fn build_meteora_instruction_audit_payload(
|
||||
return serde_json::json!({
|
||||
"decoder": protocol_name,
|
||||
"eventKind": event_kind,
|
||||
"signature": transaction.signature,
|
||||
"signature": transaction.signature.clone(),
|
||||
"instructionId": instruction.id,
|
||||
"instructionIndex": instruction.instruction_index,
|
||||
"innerInstructionIndex": instruction.inner_instruction_index,
|
||||
@@ -2023,7 +2278,7 @@ fn build_raydium_instruction_audit_payload(
|
||||
return serde_json::json!({
|
||||
"decoder": protocol_name,
|
||||
"eventKind": event_kind,
|
||||
"signature": transaction.signature,
|
||||
"signature": transaction.signature.clone(),
|
||||
"instructionId": instruction.id,
|
||||
"instructionIndex": instruction.instruction_index,
|
||||
"innerInstructionIndex": instruction.inner_instruction_index,
|
||||
@@ -2073,6 +2328,58 @@ fn candidate_raydium_audit_pool_account(
|
||||
return accounts.get(spec.candidate_pool_account_index).cloned();
|
||||
}
|
||||
|
||||
fn build_upstream_registry_instruction_match_payload(
|
||||
transaction: &crate::ChainTransactionDto,
|
||||
instruction: &crate::ChainInstructionDto,
|
||||
registry_match: &crate::UpstreamRegistryEntryDto,
|
||||
data_base58: std::option::Option<&str>,
|
||||
) -> serde_json::Value {
|
||||
let data_bytes = instruction_data_bytes_from_base58(data_base58);
|
||||
let data_byte_len = match data_bytes.as_ref() {
|
||||
Some(data_bytes) => {
|
||||
let len_result = u64::try_from(data_bytes.len());
|
||||
match len_result {
|
||||
Ok(len) => serde_json::Value::Number(serde_json::Number::from(len)),
|
||||
Err(_) => serde_json::Value::Null,
|
||||
}
|
||||
},
|
||||
None => serde_json::Value::Null,
|
||||
};
|
||||
return serde_json::json!({
|
||||
"decoder": crate::UPSTREAM_REGISTRY_PROTOCOL_NAME,
|
||||
"matchKind": "instruction_discriminator",
|
||||
"signature": transaction.signature.clone(),
|
||||
"slot": transaction.slot,
|
||||
"instructionId": instruction.id,
|
||||
"instructionIndex": instruction.instruction_index,
|
||||
"innerInstructionIndex": instruction.inner_instruction_index,
|
||||
"parentInstructionId": instruction.parent_instruction_id,
|
||||
"stackHeight": instruction.stack_height,
|
||||
"programId": instruction.program_id.clone(),
|
||||
"programName": instruction.program_name.clone(),
|
||||
"accounts": parse_instruction_accounts_value(instruction.accounts_json.as_str()),
|
||||
"accountCount": parse_instruction_accounts_vec(instruction.accounts_json.as_str()).len(),
|
||||
"dataBase58": data_base58,
|
||||
"dataByteLen": data_byte_len,
|
||||
"upstreamSourceRepo": registry_match.source_repo.clone(),
|
||||
"upstreamSourcePath": registry_match.source_path.clone(),
|
||||
"upstreamDecoderCode": registry_match.decoder_code.clone(),
|
||||
"upstreamProgramFamily": registry_match.program_family.clone(),
|
||||
"upstreamSurfaceKind": registry_match.surface_kind.clone(),
|
||||
"upstreamEntryKind": registry_match.entry_kind.clone(),
|
||||
"upstreamEntryName": registry_match.entry_name.clone(),
|
||||
"upstreamDiscriminatorHex": registry_match.discriminator_hex.clone(),
|
||||
"upstreamDiscriminatorLen": registry_match.discriminator_len,
|
||||
"upstreamProofStatus": registry_match.proof_status.clone(),
|
||||
"upstreamNotes": registry_match.notes.clone(),
|
||||
"tradeCandidate": false,
|
||||
"candleCandidate": false,
|
||||
"nonTradeUseful": false,
|
||||
"skipTradeReason": "upstream_git_unverified_registry_match",
|
||||
"skipCandleReason": "upstream_git_unverified_registry_match"
|
||||
});
|
||||
}
|
||||
|
||||
fn parse_instruction_accounts_vec(accounts_json: &str) -> std::vec::Vec<std::string::String> {
|
||||
let accounts_result = serde_json::from_str::<std::vec::Vec<std::string::String>>(accounts_json);
|
||||
match accounts_result {
|
||||
@@ -2146,6 +2453,20 @@ fn append_persisted_events(
|
||||
}
|
||||
}
|
||||
|
||||
fn decoded_instruction_ids_from_persisted_events(
|
||||
persisted: &[crate::DexDecodedEventDto],
|
||||
) -> std::collections::HashSet<i64> {
|
||||
let mut decoded_instruction_ids = std::collections::HashSet::<i64>::new();
|
||||
for decoded_event in persisted {
|
||||
let instruction_id = match decoded_event.instruction_id {
|
||||
Some(instruction_id) => instruction_id,
|
||||
None => continue,
|
||||
};
|
||||
decoded_instruction_ids.insert(instruction_id);
|
||||
}
|
||||
return decoded_instruction_ids;
|
||||
}
|
||||
|
||||
fn append_persisted_events_result(
|
||||
target: &mut std::vec::Vec<crate::DexDecodedEventDto>,
|
||||
source_result: Result<std::vec::Vec<crate::DexDecodedEventDto>, crate::Error>,
|
||||
@@ -3223,4 +3544,60 @@ mod tests {
|
||||
);
|
||||
assert_eq!(super::instruction_audit_event_kind_by_protocol("unknown"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upstream_registry_match_payload_is_never_trade_or_candle_candidate() {
|
||||
let transaction = crate::ChainTransactionDto::new(
|
||||
"upstream-registry-test-signature".to_string(),
|
||||
Some(123),
|
||||
Some(123456),
|
||||
Some("test".to_string()),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
"{}".to_string(),
|
||||
);
|
||||
let instruction = crate::ChainInstructionDto::new(
|
||||
1,
|
||||
None,
|
||||
0,
|
||||
None,
|
||||
Some(crate::METEORA_DAMM_V2_PROGRAM_ID.to_string()),
|
||||
None,
|
||||
None,
|
||||
"[]".to_string(),
|
||||
Some("data".to_string()),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let registry_match = crate::UpstreamRegistryEntryDto {
|
||||
source_repo: Some("sevenlabs-hq/carbon".to_string()),
|
||||
source_path: Some("decoders/example.rs".to_string()),
|
||||
decoder_code: "meteora-damm-v2".to_string(),
|
||||
program_id: Some(crate::METEORA_DAMM_V2_PROGRAM_ID.to_string()),
|
||||
program_family: "meteora".to_string(),
|
||||
surface_kind: "amm".to_string(),
|
||||
entry_kind: crate::ENTRY_KIND_INSTRUCTION.to_string(),
|
||||
entry_name: "swap".to_string(),
|
||||
discriminator_hex: Some("f8c69e91e17587c8".to_string()),
|
||||
discriminator_len: Some(8),
|
||||
proof_status: crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED.to_string(),
|
||||
notes: "test".to_string(),
|
||||
};
|
||||
let payload = super::build_upstream_registry_instruction_match_payload(
|
||||
&transaction,
|
||||
&instruction,
|
||||
®istry_match,
|
||||
Some("data"),
|
||||
);
|
||||
assert_eq!(payload.get("tradeCandidate").and_then(serde_json::Value::as_bool), Some(false));
|
||||
assert_eq!(
|
||||
payload.get("candleCandidate").and_then(serde_json::Value::as_bool),
|
||||
Some(false)
|
||||
);
|
||||
assert_eq!(
|
||||
payload.get("upstreamProofStatus").and_then(serde_json::Value::as_str),
|
||||
Some(crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,20 @@ impl DexDetectService {
|
||||
Some(route) => route,
|
||||
None => continue,
|
||||
};
|
||||
if crate::dex_detection_route::dex_detection_route_requires_full_pool_context(route)
|
||||
&& !crate::dex_detection_route::decoded_event_has_full_pool_context(decoded_event)
|
||||
{
|
||||
tracing::trace!(
|
||||
decoded_event_id = ?decoded_event.id,
|
||||
protocol_name = %decoded_event.protocol_name,
|
||||
event_kind = %decoded_event.event_kind,
|
||||
pool_account = ?decoded_event.pool_account,
|
||||
token_a_mint = ?decoded_event.token_a_mint,
|
||||
token_b_mint = ?decoded_event.token_b_mint,
|
||||
"skipping business-level dex detection for incomplete decoded pool context"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let detect_result = match route {
|
||||
crate::dex_detection_route::DexDetectionRoute::RaydiumAmmV4Initialize2Pool => {
|
||||
self.detect_raydium_initialize2_pool(&transaction, decoded_event).await
|
||||
|
||||
@@ -133,15 +133,122 @@ pub(crate) fn dex_detection_route(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_incomplete_pump_swap_decoded_event(decoded_event: &crate::DexDecodedEventDto) -> bool {
|
||||
/// Returns true when a route materializes a pool and therefore requires
|
||||
/// pool account plus both token mints before it can run safely.
|
||||
pub(crate) fn dex_detection_route_requires_full_pool_context(
|
||||
route: crate::dex_detection_route::DexDetectionRoute,
|
||||
) -> bool {
|
||||
match route {
|
||||
crate::dex_detection_route::DexDetectionRoute::PumpFunCreateV2Token => return false,
|
||||
crate::dex_detection_route::DexDetectionRoute::SkipIncompletePumpSwapTrade => return false,
|
||||
_ => return true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true when a decoded event has the minimum fields required for
|
||||
/// deterministic pool, pair and listing materialization.
|
||||
pub(crate) fn decoded_event_has_full_pool_context(
|
||||
decoded_event: &crate::DexDecodedEventDto,
|
||||
) -> bool {
|
||||
if decoded_event.pool_account.is_none() {
|
||||
return true;
|
||||
}
|
||||
if decoded_event.token_a_mint.is_none() {
|
||||
return true;
|
||||
}
|
||||
if decoded_event.token_b_mint.is_none() {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if decoded_event.token_a_mint.is_none() {
|
||||
return false;
|
||||
}
|
||||
if decoded_event.token_b_mint.is_none() {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn is_incomplete_pump_swap_decoded_event(decoded_event: &crate::DexDecodedEventDto) -> bool {
|
||||
return !crate::dex_detection_route::decoded_event_has_full_pool_context(decoded_event);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn make_decoded_event(
|
||||
protocol_name: &str,
|
||||
event_kind: &str,
|
||||
pool_account: std::option::Option<&str>,
|
||||
token_a_mint: std::option::Option<&str>,
|
||||
token_b_mint: std::option::Option<&str>,
|
||||
) -> crate::DexDecodedEventDto {
|
||||
return crate::DexDecodedEventDto::new(
|
||||
1,
|
||||
Some(1),
|
||||
protocol_name.to_string(),
|
||||
"Program1111111111111111111111111111111111".to_string(),
|
||||
event_kind.to_string(),
|
||||
pool_account.map(std::string::ToString::to_string),
|
||||
None,
|
||||
token_a_mint.map(std::string::ToString::to_string),
|
||||
token_b_mint.map(std::string::ToString::to_string),
|
||||
None,
|
||||
"{}".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_pool_context_requires_pool_and_two_token_mints() {
|
||||
let complete = make_decoded_event(
|
||||
"meteora_damm_v2",
|
||||
"meteora_damm_v2.swap",
|
||||
Some("Pool111"),
|
||||
Some("TokenA111"),
|
||||
Some("TokenB111"),
|
||||
);
|
||||
assert!(crate::dex_detection_route::decoded_event_has_full_pool_context(&complete));
|
||||
|
||||
let missing_token_a = make_decoded_event(
|
||||
"meteora_damm_v2",
|
||||
"meteora_damm_v2.swap",
|
||||
Some("Pool111"),
|
||||
None,
|
||||
Some("TokenB111"),
|
||||
);
|
||||
assert!(!crate::dex_detection_route::decoded_event_has_full_pool_context(
|
||||
&missing_token_a
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn meteora_swap_route_requires_full_pool_context() {
|
||||
let event = make_decoded_event(
|
||||
"meteora_damm_v2",
|
||||
"meteora_damm_v2.swap",
|
||||
Some("Pool111"),
|
||||
None,
|
||||
Some("TokenB111"),
|
||||
);
|
||||
let route_option = crate::dex_detection_route::dex_detection_route(&event);
|
||||
let route = match route_option {
|
||||
Some(route) => route,
|
||||
None => panic!("route must be selected"),
|
||||
};
|
||||
assert!(crate::dex_detection_route::dex_detection_route_requires_full_pool_context(
|
||||
route
|
||||
));
|
||||
assert!(!crate::dex_detection_route::decoded_event_has_full_pool_context(&event));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pump_fun_create_token_route_does_not_require_full_pool_context() {
|
||||
let event = make_decoded_event(
|
||||
"pump_fun",
|
||||
"pump_fun.create_v2_token",
|
||||
Some("BondingCurve111"),
|
||||
Some("TokenA111"),
|
||||
None,
|
||||
);
|
||||
let route_option = crate::dex_detection_route::dex_detection_route(&event);
|
||||
let route = match route_option {
|
||||
Some(route) => route,
|
||||
None => panic!("route must be selected"),
|
||||
};
|
||||
assert!(!crate::dex_detection_route::dex_detection_route_requires_full_pool_context(
|
||||
route
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,9 +266,15 @@ pub fn classify_dex_event_actionability_code(
|
||||
|
||||
/// Returns true for decoded audit-only events retained for corpus analysis.
|
||||
pub fn is_dex_informational_event_kind(event_kind: &str) -> bool {
|
||||
if event_kind == crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".instruction_audit") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.ends_with("_audit") {
|
||||
return true;
|
||||
}
|
||||
if event_kind.contains(".unknown_instruction") {
|
||||
return true;
|
||||
}
|
||||
@@ -1145,4 +1151,38 @@ mod tests {
|
||||
"non_trade_useful"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_audit_suffix_events_as_informational() {
|
||||
assert!(super::is_dex_informational_event_kind("openbook_v2.settle_funds_audit"));
|
||||
assert_eq!(
|
||||
super::classify_dex_event_category_code("openbook_v2.settle_funds_audit"),
|
||||
"informational"
|
||||
);
|
||||
assert_eq!(
|
||||
super::classify_dex_event_actionability_code(
|
||||
"openbook_v2.settle_funds_audit",
|
||||
false,
|
||||
false,
|
||||
),
|
||||
"informational"
|
||||
);
|
||||
assert!(!super::is_dex_trade_event_kind("openbook_v2.order_place_audit"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_upstream_registry_instruction_match_as_informational() {
|
||||
assert!(super::is_dex_informational_event_kind(
|
||||
crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND
|
||||
));
|
||||
assert_eq!(
|
||||
super::classify_dex_event_category_code(
|
||||
crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND
|
||||
),
|
||||
"informational"
|
||||
);
|
||||
assert!(!super::is_dex_trade_event_kind(
|
||||
crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,13 +13,7 @@ struct BuiltinLaunchSurfaceSpec {
|
||||
const BUILTIN_LAUNCH_SURFACE_SPECS: &[BuiltinLaunchSurfaceSpec] = &[
|
||||
BuiltinLaunchSurfaceSpec {
|
||||
code: "raydium_launchlab",
|
||||
name: "Raydium LaunchLab",
|
||||
protocol_family: "raydium",
|
||||
enabled: true,
|
||||
},
|
||||
BuiltinLaunchSurfaceSpec {
|
||||
code: "raydium_launchpad",
|
||||
name: "Raydium Launchpad",
|
||||
name: "Raydium LaunchLab / Launchpad",
|
||||
protocol_family: "raydium",
|
||||
enabled: true,
|
||||
},
|
||||
@@ -988,10 +982,9 @@ mod tests {
|
||||
Ok(surface_ids) => surface_ids,
|
||||
Err(error) => panic!("target launch surfaces must seed: {}", error),
|
||||
};
|
||||
assert_eq!(surface_ids.len(), 10);
|
||||
assert_eq!(surface_ids.len(), 9);
|
||||
let required_codes = [
|
||||
"raydium_launchlab",
|
||||
"raydium_launchpad",
|
||||
"letsbonk",
|
||||
"bonk_fun",
|
||||
"bags",
|
||||
|
||||
@@ -111,6 +111,14 @@ mod tx_model;
|
||||
mod tx_resolution;
|
||||
/// Shared generic types for `kb_lib`.
|
||||
mod types;
|
||||
/// Upstream Git registry service facade.
|
||||
mod upstream_registry;
|
||||
/// Static upstream Git registry bootstrap data.
|
||||
mod upstream_registry_generated;
|
||||
/// Upstream Git registry matching helpers.
|
||||
mod upstream_registry_match;
|
||||
/// Upstream Git registry DTOs and static entry types.
|
||||
mod upstream_registry_types;
|
||||
/// Wallet-holding observation service.
|
||||
mod wallet_holding_observation;
|
||||
/// Wallet-observation service.
|
||||
@@ -147,19 +155,37 @@ pub use config::WsEndpointConfig;
|
||||
/// Address Lookup Table program identifier. ("AddressLookupTab1e1111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::address_lookup_table::ID
|
||||
pub use constants::ADDRESS_LOOKUP_TABLE_PROGRAM_ID;
|
||||
/// AlphaQ program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::ALPHAQ_PROGRAM_ID;
|
||||
/// Aquifer program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::AQUIFER_PROGRAM_ID;
|
||||
/// Arbitrage Bot (6MWVT) / Arbitrage or Sandwich Bot. ("6MWVTis8rmmk6Vt9zmAJJbmb3VuLpzoQ1aHH4N6wQEGh").
|
||||
pub use constants::ARBITRAGE_BOT_6MWVT_PROGRAM_ID;
|
||||
/// Associated Token Account program identifier. ("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").
|
||||
/// @see solana_sdk::pubkey::Pubkey = spl_associated_token_account_interface::program::ID
|
||||
pub use constants::ASSOCIATED_TOKEN_PROGRAM_ID;
|
||||
/// BisonFi program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::BISONFI_PROGRAM_ID;
|
||||
/// Canonical Bonk token mint identifier.
|
||||
pub use constants::BONK_MINT_ID;
|
||||
/// Bonkswap program id extracted from upstream Git decoder source.
|
||||
pub use constants::BONKSWAP_PROGRAM_ID;
|
||||
/// Boop program id extracted from upstream Git decoder source.
|
||||
pub use constants::BOOP_PROGRAM_ID;
|
||||
/// BPF Loader program identifier. ("BPFLoader1111111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::bpf_loader_deprecated::ID
|
||||
pub use constants::BPF_LOADER_DEPRECATED_PROGRAM_ID;
|
||||
/// BPF Loader program identifier. ("BPFLoaderUpgradeab1e11111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::bpf_loader_upgradeable::ID
|
||||
pub use constants::BPF_LOADER_UPGRADEABLE_PROGRAM_ID;
|
||||
/// Bubblegum program id extracted from upstream Git decoder source.
|
||||
pub use constants::BUBBLEGUM_PROGRAM_ID;
|
||||
/// Byreal program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::BYREAL_PROGRAM_ID;
|
||||
/// Circle Message Transmitter v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::CIRCLE_MESSAGE_TRANSMITTER_V2_PROGRAM_ID;
|
||||
/// Circle Token Messenger v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::CIRCLE_TOKEN_MESSENGER_V2_PROGRAM_ID;
|
||||
/// Compute Budget program identifier. ("ComputeBudget111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::compute_budget::ID
|
||||
pub use constants::COMPUTE_BUDGET_PROGRAM_ID;
|
||||
@@ -168,6 +194,10 @@ pub use constants::COMPUTE_BUDGET_PROGRAM_ID;
|
||||
pub use constants::CONFIG_PROGRAM_ID;
|
||||
/// DexLab Swap/Pool program id. ("DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N").
|
||||
pub use constants::DEXLAB_PROGRAM_ID;
|
||||
/// DFlow Aggregator v4 program id extracted from upstream Git decoder source.
|
||||
pub use constants::DFLOW_AGGREGATOR_V4_PROGRAM_ID;
|
||||
/// Drift v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::DRIFT_V2_PROGRAM_ID;
|
||||
/// ED25519 program identifier. ("Ed25519SigVerify111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::ed25519_program::ID
|
||||
pub use constants::ED25519_PROGRAM_ID;
|
||||
@@ -176,14 +206,58 @@ pub use constants::ED25519_PROGRAM_ID;
|
||||
pub use constants::FEATURE_PROGRAM_ID;
|
||||
/// FluxBeam program id. ("FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X").
|
||||
pub use constants::FLUXBEAM_PROGRAM_ID;
|
||||
/// FusionAMM program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::FUSIONAMM_PROGRAM_ID;
|
||||
/// Gavel program id extracted from upstream Git decoder source.
|
||||
pub use constants::GAVEL_PROGRAM_ID;
|
||||
/// Goonfi program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::GOONFI_PROGRAM_ID;
|
||||
/// Goonfi v2 program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::GOONFI_V2_PROGRAM_ID;
|
||||
/// GooseFX v1 program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::GOOSEFX_V1_PROGRAM_ID;
|
||||
/// Heaven program id extracted from upstream Git decoder source.
|
||||
pub use constants::HEAVEN_PROGRAM_ID;
|
||||
/// Humidifi program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::HUMIDIFI_PROGRAM_ID;
|
||||
/// Incinerator program identifier. ("1nc1nerator11111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::incinerator::ID
|
||||
pub use constants::INCINERATOR_PROGRAM_ID;
|
||||
/// Canonical Jupiter governance token mint identifier.
|
||||
pub use constants::JUP_MINT_ID;
|
||||
/// Jupiter DCA program id extracted from upstream Git decoder source.
|
||||
pub use constants::JUPITER_DCA_PROGRAM_ID;
|
||||
/// Jupiter Lend program id extracted from upstream Git decoder source.
|
||||
pub use constants::JUPITER_LEND_PROGRAM_ID;
|
||||
/// Jupiter Limit Order 2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::JUPITER_LIMIT_ORDER_2_PROGRAM_ID;
|
||||
/// Jupiter Limit Order program id extracted from upstream Git decoder source.
|
||||
pub use constants::JUPITER_LIMIT_ORDER_PROGRAM_ID;
|
||||
/// Jupiter Perpetuals program id extracted from upstream Git decoder source.
|
||||
pub use constants::JUPITER_PERPETUALS_PROGRAM_ID;
|
||||
/// Jupiter Swap program id extracted from upstream Git decoder source.
|
||||
pub use constants::JUPITER_SWAP_PROGRAM_ID;
|
||||
/// Kamino Farms program id extracted from upstream Git decoder source.
|
||||
pub use constants::KAMINO_FARMS_PROGRAM_ID;
|
||||
/// Kamino Lending program id extracted from upstream Git decoder source.
|
||||
pub use constants::KAMINO_LENDING_PROGRAM_ID;
|
||||
/// Kamino Limit Order program id extracted from upstream Git decoder source.
|
||||
pub use constants::KAMINO_LIMIT_ORDER_PROGRAM_ID;
|
||||
/// Kamino Vault program id extracted from upstream Git decoder source.
|
||||
pub use constants::KAMINO_VAULT_PROGRAM_ID;
|
||||
/// Lifinity AMM v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::LIFINITY_AMM_V2_PROGRAM_ID;
|
||||
/// Loader V4 program identifier. ("LoaderV411111111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::loader_v4::ID
|
||||
pub use constants::LOADER_V4_PROGRAM_ID;
|
||||
/// Manifest CLOB program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::MANIFEST_CLOB_PROGRAM_ID;
|
||||
/// Marginfi v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::MARGINFI_V2_PROGRAM_ID;
|
||||
/// Marinade Finance program id extracted from upstream Git decoder source.
|
||||
pub use constants::MARINADE_FINANCE_PROGRAM_ID;
|
||||
/// SPL Memo program id.
|
||||
pub use constants::MEMO_PROGRAM_ID;
|
||||
/// MetaDAO AMM v0.5.0 program id.
|
||||
pub use constants::METADAO_AMM_V0_5_0_PROGRAM_ID;
|
||||
/// MetaDAO Bid Wall v0.7.0 program id.
|
||||
@@ -192,12 +266,6 @@ pub use constants::METADAO_BID_WALL_V0_7_0_PROGRAM_ID;
|
||||
pub use constants::METADAO_FUTARCHY_V0_6_0_PROGRAM_ID;
|
||||
/// MetaDAO Launchpad v0.7.0 program id.
|
||||
pub use constants::METADAO_LAUNCHPAD_V0_7_0_PROGRAM_ID;
|
||||
/// MetaDAO META active token mint identifier.
|
||||
pub use constants::METADAO_META_MINT_ID;
|
||||
/// MetaDAO METAC legacy token mint identifier.
|
||||
pub use constants::METADAO_METAC_LEGACY_MINT_ID;
|
||||
/// MetaDAO-linked P2P token mint candidate.
|
||||
pub use constants::METADAO_P2P_MINT_ID;
|
||||
/// Meteora DAMM v1 program id. ("Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB").
|
||||
pub use constants::METEORA_DAMM_V1_PROGRAM_ID;
|
||||
/// Meteora DAMM v2 program id. ("cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG").
|
||||
@@ -206,13 +274,39 @@ pub use constants::METEORA_DAMM_V2_PROGRAM_ID;
|
||||
pub use constants::METEORA_DBC_PROGRAM_ID;
|
||||
/// Meteora DLMM program id. ("LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo").
|
||||
pub use constants::METEORA_DLMM_PROGRAM_ID;
|
||||
/// Meteora Vault program id extracted from upstream Git decoder source.
|
||||
pub use constants::METEORA_VAULT_PROGRAM_ID;
|
||||
/// Moonshot program id extracted from upstream Git decoder source.
|
||||
pub use constants::MOONSHOT_PROGRAM_ID;
|
||||
/// MPL Core program id extracted from upstream Git decoder source.
|
||||
pub use constants::MPL_CORE_PROGRAM_ID;
|
||||
/// MPL Token Metadata program id extracted from upstream Git decoder source.
|
||||
pub use constants::MPL_TOKEN_METADATA_PROGRAM_ID;
|
||||
/// Solana Name Service program id extracted from upstream Git decoder source.
|
||||
pub use constants::NAME_SERVICE_PROGRAM_ID;
|
||||
/// Native Loader program identifier. ("NativeLoader1111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::native_loader::ID
|
||||
pub use constants::NATIVE_LOADER_PROGRAM_ID;
|
||||
/// Obric v2 program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::OBRIC_V2_PROGRAM_ID;
|
||||
/// OKX DEX program id extracted from upstream Git decoder source.
|
||||
pub use constants::OKX_DEX_PROGRAM_ID;
|
||||
/// Onchain Labs DEX v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::ONCHAIN_LABS_DEX_V2_PROGRAM_ID;
|
||||
/// Ondo Global Market program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::ONDO_GLOBAL_MARKET_PROGRAM_ID;
|
||||
/// OpenBook v2 program id extracted from upstream Git decoder source.
|
||||
pub use constants::OPENBOOK_V2_PROGRAM_ID;
|
||||
/// Orca Whirlpools program id. ("whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc").
|
||||
pub use constants::ORCA_WHIRLPOOLS_PROGRAM_ID;
|
||||
/// Pancake Swap program id extracted from upstream Git decoder source.
|
||||
pub use constants::PANCAKE_SWAP_PROGRAM_ID;
|
||||
/// Phoenix v1 program id extracted from upstream Git decoder source.
|
||||
pub use constants::PHOENIX_V1_PROGRAM_ID;
|
||||
/// Printr program id candidate observed on Solscan.
|
||||
pub use constants::PRINTR_PROGRAM_ID;
|
||||
/// Pump Fees program id extracted from upstream Git decoder source.
|
||||
pub use constants::PUMP_FEES_PROGRAM_ID;
|
||||
/// Pump.fun program id. ("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P").
|
||||
pub use constants::PUMP_FUN_PROGRAM_ID;
|
||||
/// PumpSwap / PumpAMM program id. ("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA").
|
||||
@@ -227,28 +321,44 @@ pub use constants::RAYDIUM_AMM_V4_PROGRAM_ID;
|
||||
pub use constants::RAYDIUM_CLMM_PROGRAM_ID;
|
||||
/// Raydium CPMM mainnet program id. ("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C").
|
||||
pub use constants::RAYDIUM_CPMM_PROGRAM_ID;
|
||||
/// Raydium LaunchLab program id. ("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj").
|
||||
/// Raydium LaunchLab / Launchpad program id. ("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj").
|
||||
pub use constants::RAYDIUM_LAUNCHLAB_PROGRAM_ID;
|
||||
/// Raydium Liquidity Locking program id extracted from upstream Git decoder source.
|
||||
pub use constants::RAYDIUM_LIQUIDITY_LOCKING_PROGRAM_ID;
|
||||
/// Raydium Stable Swap AMM program id, deprecated. ("5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h").
|
||||
pub use constants::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID;
|
||||
/// Scorch program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::SCORCH_PROGRAM_ID;
|
||||
/// Secp256k1 program identifier. ("KeccakSecp256k11111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::secp256k1_program::ID
|
||||
pub use constants::SECP256K1_PROGRAM_ID;
|
||||
/// Secp256r1 program identifier. ("Secp256r1SigVerify1111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::secp256r1_program::ID
|
||||
pub use constants::SECP256R1_PROGRAM_ID;
|
||||
/// Sharky program id extracted from upstream Git decoder source.
|
||||
pub use constants::SHARKY_PROGRAM_ID;
|
||||
/// Solayer Restaking program id extracted from upstream Git decoder source.
|
||||
pub use constants::SOLAYER_RESTAKING_PROGRAM_ID;
|
||||
/// SolFi v2 program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::SOLFI_V2_PROGRAM_ID;
|
||||
/// SPL Token-2022 program identifier. ("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb").
|
||||
/// @see solana_sdk::pubkey::Pubkey = spl_token_2022_interface::ID
|
||||
pub use constants::SPL_TOKEN_2022_PROGRAM_ID;
|
||||
/// SPL Token program identifier. ("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA").
|
||||
/// @see solana_sdk::pubkey::Pubkey = spl_token_interface::ID
|
||||
pub use constants::SPL_TOKEN_PROGRAM_ID;
|
||||
/// Stabble stable-swap program id extracted from upstream Git decoder source.
|
||||
pub use constants::STABBLE_STABLE_SWAP_PROGRAM_ID;
|
||||
/// Stabble weighted-swap program id extracted from upstream Git decoder source.
|
||||
pub use constants::STABBLE_WEIGHTED_SWAP_PROGRAM_ID;
|
||||
/// Stake Config program identifier. ("StakeConfig11111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::stake::config::ID
|
||||
pub use constants::STAKE_CONFIG_PROGRAM_ID;
|
||||
/// Stake program identifier. ("Stake11111111111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::stake::ID
|
||||
pub use constants::STAKE_PROGRAM_ID;
|
||||
/// Swig program id extracted from upstream Git decoder source.
|
||||
pub use constants::SWIG_PROGRAM_ID;
|
||||
/// System program identifier. ("11111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::system_program::ID
|
||||
pub use constants::SYSTEM_PROGRAM_ID;
|
||||
@@ -295,12 +405,24 @@ pub use constants::SYSVAR_STAKE_HISTORY_PROGRAM_ID;
|
||||
pub use constants::USDC_MINT_ID;
|
||||
/// Canonical Solana USDT mint identifier.
|
||||
pub use constants::USDT_MINT_ID;
|
||||
/// Vertigo program id extracted from upstream Git decoder source.
|
||||
pub use constants::VERTIGO_PROGRAM_ID;
|
||||
/// Virtuals program id extracted from upstream Git decoder source.
|
||||
pub use constants::VIRTUALS_PROGRAM_ID;
|
||||
/// Vote program identifier. ("Vote111111111111111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::vote::ID
|
||||
pub use constants::VOTE_PROGRAM_ID;
|
||||
/// Wavebreak program id extracted from upstream Git decoder source.
|
||||
pub use constants::WAVEBREAK_PROGRAM_ID;
|
||||
/// Woofi program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::WOOFI_PROGRAM_ID;
|
||||
/// Wrapped SOL mint identifier. ("So11111111111111111111111111111111111111112").
|
||||
/// @see solana_sdk::pubkey::Pubkey = spl_token_interface::native_mint::ID
|
||||
pub use constants::WSOL_MINT_ID;
|
||||
/// ZeroFi program id from Vybe supported DEX/AMM documentation.
|
||||
pub use constants::ZEROFI_PROGRAM_ID;
|
||||
/// Zeta program id extracted from upstream Git decoder source.
|
||||
pub use constants::ZETA_PROGRAM_ID;
|
||||
/// Zk El Gamal Proof program identifier. ("ZkE1Gama1Proof11111111111111111111111111111").
|
||||
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::zk_elgamal_proof_program::ID
|
||||
pub use constants::ZK_ELGAMAL_PROOF_PROGRAM_ID;
|
||||
@@ -943,6 +1065,12 @@ pub use dex::MeteoraDlmmPoolLifecycleDecoded;
|
||||
pub use dex::MeteoraDlmmRewardDecoded;
|
||||
/// Decoded Meteora DLMM swap event.
|
||||
pub use dex::MeteoraDlmmSwapDecoded;
|
||||
/// Decoded OpenBook v2 audit event.
|
||||
pub use dex::OpenBookV2AuditDecoded;
|
||||
/// Decoded OpenBook v2 event.
|
||||
pub use dex::OpenBookV2DecodedEvent;
|
||||
/// OpenBook v2 audit-only decoder.
|
||||
pub use dex::OpenBookV2Decoder;
|
||||
/// Decoded Orca Whirlpools create-pool event.
|
||||
pub use dex::OrcaWhirlpoolsCreatePoolDecoded;
|
||||
/// Decoded Orca Whirlpools event.
|
||||
@@ -951,6 +1079,12 @@ pub use dex::OrcaWhirlpoolsDecodedEvent;
|
||||
pub use dex::OrcaWhirlpoolsDecoder;
|
||||
/// Decoded Orca Whirlpools swap event.
|
||||
pub use dex::OrcaWhirlpoolsSwapDecoded;
|
||||
/// Decoded Phoenix v1 audit event.
|
||||
pub use dex::PhoenixV1AuditDecoded;
|
||||
/// Decoded Phoenix v1 event.
|
||||
pub use dex::PhoenixV1DecodedEvent;
|
||||
/// Phoenix v1 audit-only decoder.
|
||||
pub use dex::PhoenixV1Decoder;
|
||||
/// Decoded Pump.fun `create_v2` token event.
|
||||
pub use dex::PumpFunCreateV2TokenDecoded;
|
||||
/// Decoded Pump.fun event.
|
||||
@@ -1164,8 +1298,12 @@ pub use local_pipeline_validation::validate_local_pipeline_diagnostics_summary;
|
||||
pub use non_trade_event_materialization::NonTradeEventMaterializationResult;
|
||||
/// Materializes useful non-trade decoded DEX events.
|
||||
pub use non_trade_event_materialization::NonTradeEventMaterializationService;
|
||||
/// Backfill signatures grouped by candidate kind.
|
||||
pub use onchain_dex_pair_discovery::OnchainDexBackfillSignaturesByKindDto;
|
||||
/// Candidate account inferred from generic transaction evidence.
|
||||
pub use onchain_dex_pair_discovery::OnchainDexCandidateAccountDto;
|
||||
/// Candidate summary grouped by kind and transaction success state.
|
||||
pub use onchain_dex_pair_discovery::OnchainDexCandidateKindSummaryDto;
|
||||
/// Cursor hint for one on-chain DEX discovery source address.
|
||||
pub use onchain_dex_pair_discovery::OnchainDexPaginationCursorDto;
|
||||
/// Candidate transaction/instruction observed on-chain for one DEX program id.
|
||||
@@ -1266,6 +1404,40 @@ pub use tx_resolution::WsTransactionResolutionRelay;
|
||||
pub use tx_resolution::WsTransactionResolutionRelayStats;
|
||||
/// Generic connection state used by transport clients.
|
||||
pub use types::ConnectionState;
|
||||
/// Read-only upstream registry service.
|
||||
pub use upstream_registry::UpstreamRegistryService;
|
||||
/// Static upstream registry entry kind for account layouts.
|
||||
pub use upstream_registry_types::ENTRY_KIND_ACCOUNT;
|
||||
/// Static upstream registry entry kind for events.
|
||||
pub use upstream_registry_types::ENTRY_KIND_EVENT;
|
||||
/// Static upstream registry entry kind for instructions.
|
||||
pub use upstream_registry_types::ENTRY_KIND_INSTRUCTION;
|
||||
/// Static upstream registry entry kind for programs.
|
||||
pub use upstream_registry_types::ENTRY_KIND_PROGRAM;
|
||||
/// Generic upstream Git proof status for layout-only unverified entries.
|
||||
pub use upstream_registry_types::PROOF_STATUS_UPSTREAM_GIT_LAYOUT_UNVERIFIED;
|
||||
/// Generic upstream Git proof status for locally materialized entries.
|
||||
pub use upstream_registry_types::PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_MATERIALIZED;
|
||||
/// Generic upstream Git proof status for locally observed entries.
|
||||
pub use upstream_registry_types::PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_OBSERVED;
|
||||
/// Generic upstream Git proof status for decoder-mapped unverified entries.
|
||||
pub use upstream_registry_types::PROOF_STATUS_UPSTREAM_GIT_MAPPED_UNVERIFIED;
|
||||
/// Generic upstream Git proof status for unverified entries.
|
||||
pub use upstream_registry_types::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED;
|
||||
/// Generic event kind used for instruction-level upstream registry matches.
|
||||
pub use upstream_registry_types::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND;
|
||||
/// Generic protocol name used for upstream registry matches that are not business-materialized.
|
||||
pub use upstream_registry_types::UPSTREAM_REGISTRY_PROTOCOL_NAME;
|
||||
/// Static upstream registry entry.
|
||||
pub use upstream_registry_types::UpstreamRegistryEntry;
|
||||
/// Owned upstream registry entry DTO.
|
||||
pub use upstream_registry_types::UpstreamRegistryEntryDto;
|
||||
/// Upstream registry search request DTO.
|
||||
pub use upstream_registry_types::UpstreamRegistrySearchRequestDto;
|
||||
/// Upstream registry search result DTO.
|
||||
pub use upstream_registry_types::UpstreamRegistrySearchResultDto;
|
||||
/// Upstream registry summary DTO.
|
||||
pub use upstream_registry_types::UpstreamRegistrySummaryDto;
|
||||
/// One wallet-holding observation result.
|
||||
pub use wallet_holding_observation::WalletHoldingObservationResult;
|
||||
/// Wallet-holding observation service.
|
||||
|
||||
@@ -658,7 +658,7 @@ fn build_success_dex_decode_replay_ledger(
|
||||
fn count_effective_decoded_events(decoded_events: &[crate::DexDecodedEventDto]) -> usize {
|
||||
let mut count = 0_usize;
|
||||
for event in decoded_events {
|
||||
if is_instruction_audit_event(event) {
|
||||
if is_replay_audit_only_event(event) {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
@@ -666,8 +666,17 @@ fn count_effective_decoded_events(decoded_events: &[crate::DexDecodedEventDto])
|
||||
return count;
|
||||
}
|
||||
|
||||
fn is_instruction_audit_event(event: &crate::DexDecodedEventDto) -> bool {
|
||||
return event.event_kind.ends_with(".instruction_audit");
|
||||
fn is_replay_audit_only_event(event: &crate::DexDecodedEventDto) -> bool {
|
||||
if event.event_kind.ends_with(".instruction_audit") {
|
||||
return true;
|
||||
}
|
||||
if event.event_kind.ends_with("_audit") {
|
||||
return true;
|
||||
}
|
||||
if event.event_kind == crate::UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn count_distinct_decoded_event_token_mints(decoded_events: &[crate::DexDecodedEventDto]) -> usize {
|
||||
@@ -759,6 +768,20 @@ mod tests {
|
||||
assert!(ledger.can_skip_decode());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ledger_treats_audit_suffix_events_as_audit_only() {
|
||||
let events = vec![
|
||||
make_decoded_event("openbook_v2.settle_funds_audit", Some("mint-a"), Some("mint-b")),
|
||||
make_decoded_event("openbook_v2.order_place_audit", None, None),
|
||||
];
|
||||
let ledger = super::build_success_dex_decode_replay_ledger(1, "sig", events.as_slice())
|
||||
.expect("ledger must build");
|
||||
assert_eq!(ledger.event_count, 2);
|
||||
assert_eq!(ledger.status_reason.as_deref(), Some("decode completed and certified for skip: event_count=2, effective_event_count=0, instruction_audit_count=2, distinct_token_mint_count=2"));
|
||||
assert!(!ledger.force_replay_required);
|
||||
assert!(ledger.can_skip_decode());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ledger_keeps_multiple_effective_events_unsafe() {
|
||||
let events = vec![
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
58
kb_lib/src/upstream_registry.rs
Normal file
58
kb_lib/src/upstream_registry.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
// file: kb_lib/src/upstream_registry.rs
|
||||
|
||||
//! Public service facade for the upstream Git registry.
|
||||
//!
|
||||
//! The registry is intentionally read-only in this tranche and does not touch
|
||||
//! SQLite. It only exposes discovery seeds and static upstream-derived metadata
|
||||
//! for UI inspection and later corpus validation.
|
||||
|
||||
/// Read-only upstream registry service.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct UpstreamRegistryService;
|
||||
|
||||
impl UpstreamRegistryService {
|
||||
/// Creates a new read-only upstream registry service.
|
||||
pub fn new() -> crate::UpstreamRegistryService {
|
||||
return crate::UpstreamRegistryService;
|
||||
}
|
||||
|
||||
/// Returns every static registry entry.
|
||||
pub fn all_entries(&self) -> std::vec::Vec<crate::UpstreamRegistryEntryDto> {
|
||||
return crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
}
|
||||
|
||||
/// Searches the static registry with optional filters.
|
||||
pub fn search(
|
||||
&self,
|
||||
request: &crate::UpstreamRegistrySearchRequestDto,
|
||||
) -> crate::UpstreamRegistrySearchResultDto {
|
||||
return crate::upstream_registry_match::upstream_registry_search(request);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn service_returns_static_registry_entries() {
|
||||
let service = crate::UpstreamRegistryService::new();
|
||||
let entries = service.all_entries();
|
||||
assert!(!entries.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn service_search_preserves_normalized_request() {
|
||||
let service = crate::UpstreamRegistryService::new();
|
||||
let request = crate::UpstreamRegistrySearchRequestDto {
|
||||
decoder_code: Some("raydium-cpmm".to_string()),
|
||||
program_id: None,
|
||||
program_family: None,
|
||||
surface_kind: None,
|
||||
entry_kind: None,
|
||||
proof_status: None,
|
||||
limit: Some(10),
|
||||
};
|
||||
let result = service.search(&request);
|
||||
assert_eq!(result.request, request);
|
||||
assert!(!result.entries.is_empty());
|
||||
}
|
||||
}
|
||||
15595
kb_lib/src/upstream_registry_generated.rs
Normal file
15595
kb_lib/src/upstream_registry_generated.rs
Normal file
File diff suppressed because it is too large
Load Diff
651
kb_lib/src/upstream_registry_match.rs
Normal file
651
kb_lib/src/upstream_registry_match.rs
Normal file
@@ -0,0 +1,651 @@
|
||||
// file: kb_lib/src/upstream_registry_match.rs
|
||||
|
||||
//! Matching, filtering and summarizing helpers for the upstream Git registry.
|
||||
|
||||
/// Returns all static upstream registry entries as owned DTOs.
|
||||
pub(crate) fn upstream_registry_all_entries() -> std::vec::Vec<crate::UpstreamRegistryEntryDto> {
|
||||
let mut entries = std::vec::Vec::new();
|
||||
for entry in crate::upstream_registry_generated::UPSTREAM_REGISTRY_ENTRIES {
|
||||
entries.push(entry.to_dto());
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/// Searches static upstream registry entries with optional filters.
|
||||
pub(crate) fn upstream_registry_search(
|
||||
request: &crate::UpstreamRegistrySearchRequestDto,
|
||||
) -> crate::UpstreamRegistrySearchResultDto {
|
||||
let total_entry_count = crate::upstream_registry_generated::UPSTREAM_REGISTRY_ENTRIES.len();
|
||||
let mut entries = std::vec::Vec::new();
|
||||
for entry in crate::upstream_registry_generated::UPSTREAM_REGISTRY_ENTRIES {
|
||||
if !matches_request(entry, request) {
|
||||
continue;
|
||||
}
|
||||
entries.push(entry.to_dto());
|
||||
if let Some(limit) = request.limit {
|
||||
if entries.len() >= limit {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let summary = summarize(total_entry_count, entries.as_slice());
|
||||
return crate::UpstreamRegistrySearchResultDto {
|
||||
request: request.clone(),
|
||||
summary,
|
||||
entries,
|
||||
};
|
||||
}
|
||||
|
||||
fn matches_request(
|
||||
entry: &crate::UpstreamRegistryEntry,
|
||||
request: &crate::UpstreamRegistrySearchRequestDto,
|
||||
) -> bool {
|
||||
if !matches_string_filter(entry.decoder_code, &request.decoder_code) {
|
||||
return false;
|
||||
}
|
||||
if !matches_optional_string_filter(entry.program_id, &request.program_id) {
|
||||
return false;
|
||||
}
|
||||
if !matches_string_filter(entry.program_family, &request.program_family) {
|
||||
return false;
|
||||
}
|
||||
if !matches_string_filter(entry.surface_kind, &request.surface_kind) {
|
||||
return false;
|
||||
}
|
||||
if !matches_string_filter(entry.entry_kind, &request.entry_kind) {
|
||||
return false;
|
||||
}
|
||||
if !matches_string_filter(entry.proof_status, &request.proof_status) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn matches_string_filter(value: &str, filter: &std::option::Option<std::string::String>) -> bool {
|
||||
let filter_value = match filter {
|
||||
Some(filter_value) => filter_value.trim(),
|
||||
None => return true,
|
||||
};
|
||||
if filter_value.is_empty() {
|
||||
return true;
|
||||
}
|
||||
return value.eq_ignore_ascii_case(filter_value);
|
||||
}
|
||||
|
||||
fn matches_optional_string_filter(
|
||||
value: std::option::Option<&str>,
|
||||
filter: &std::option::Option<std::string::String>,
|
||||
) -> bool {
|
||||
let filter_value = match filter {
|
||||
Some(filter_value) => filter_value.trim(),
|
||||
None => return true,
|
||||
};
|
||||
if filter_value.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let value = match value {
|
||||
Some(value) => value,
|
||||
None => return false,
|
||||
};
|
||||
return value.eq_ignore_ascii_case(filter_value);
|
||||
}
|
||||
|
||||
fn summarize(
|
||||
total_entry_count: usize,
|
||||
entries: &[crate::UpstreamRegistryEntryDto],
|
||||
) -> crate::UpstreamRegistrySummaryDto {
|
||||
let mut entries_with_program_id_count = 0_usize;
|
||||
let mut entries_with_discriminator_count = 0_usize;
|
||||
let mut program_entry_count = 0_usize;
|
||||
let mut instruction_entry_count = 0_usize;
|
||||
let mut event_entry_count = 0_usize;
|
||||
let mut account_entry_count = 0_usize;
|
||||
let mut upstream_git_unverified_count = 0_usize;
|
||||
let mut upstream_git_mapped_unverified_count = 0_usize;
|
||||
let mut upstream_git_local_corpus_observed_count = 0_usize;
|
||||
let mut upstream_git_local_corpus_materialized_count = 0_usize;
|
||||
let mut upstream_git_layout_unverified_count = 0_usize;
|
||||
|
||||
for entry in entries {
|
||||
if entry.program_id.is_some() {
|
||||
entries_with_program_id_count += 1;
|
||||
}
|
||||
if entry.discriminator_hex.is_some() {
|
||||
entries_with_discriminator_count += 1;
|
||||
}
|
||||
match entry.entry_kind.as_str() {
|
||||
crate::ENTRY_KIND_PROGRAM => program_entry_count += 1,
|
||||
crate::ENTRY_KIND_INSTRUCTION => instruction_entry_count += 1,
|
||||
crate::ENTRY_KIND_EVENT => event_entry_count += 1,
|
||||
crate::ENTRY_KIND_ACCOUNT => account_entry_count += 1,
|
||||
_ => (),
|
||||
}
|
||||
match entry.proof_status.as_str() {
|
||||
crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED => upstream_git_unverified_count += 1,
|
||||
crate::PROOF_STATUS_UPSTREAM_GIT_MAPPED_UNVERIFIED => {
|
||||
upstream_git_mapped_unverified_count += 1;
|
||||
},
|
||||
crate::PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_OBSERVED => {
|
||||
upstream_git_local_corpus_observed_count += 1;
|
||||
},
|
||||
crate::PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_MATERIALIZED => {
|
||||
upstream_git_local_corpus_materialized_count += 1;
|
||||
},
|
||||
crate::PROOF_STATUS_UPSTREAM_GIT_LAYOUT_UNVERIFIED => {
|
||||
upstream_git_layout_unverified_count += 1;
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
return crate::UpstreamRegistrySummaryDto {
|
||||
total_entry_count,
|
||||
returned_entry_count: entries.len(),
|
||||
entries_with_program_id_count,
|
||||
entries_with_discriminator_count,
|
||||
program_entry_count,
|
||||
instruction_entry_count,
|
||||
event_entry_count,
|
||||
account_entry_count,
|
||||
upstream_git_unverified_count,
|
||||
upstream_git_mapped_unverified_count,
|
||||
upstream_git_local_corpus_observed_count,
|
||||
upstream_git_local_corpus_materialized_count,
|
||||
upstream_git_layout_unverified_count,
|
||||
};
|
||||
}
|
||||
|
||||
/// Matches raw base58 instruction data against upstream registry discriminator entries.
|
||||
pub(crate) fn upstream_registry_match_instruction_data(
|
||||
program_id: &str,
|
||||
data_base58: std::option::Option<&str>,
|
||||
) -> std::option::Option<crate::UpstreamRegistryEntryDto> {
|
||||
let data = decode_base58_instruction_data(data_base58);
|
||||
let data = match data {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
let mut selected_entry: std::option::Option<&crate::UpstreamRegistryEntry> = None;
|
||||
let mut selected_len = 0_usize;
|
||||
for entry in crate::upstream_registry_generated::UPSTREAM_REGISTRY_ENTRIES {
|
||||
if entry.entry_kind != crate::ENTRY_KIND_INSTRUCTION {
|
||||
continue;
|
||||
}
|
||||
let entry_program_id = match entry.program_id {
|
||||
Some(entry_program_id) => entry_program_id,
|
||||
None => continue,
|
||||
};
|
||||
if entry_program_id != program_id {
|
||||
continue;
|
||||
}
|
||||
let discriminator_hex = match entry.discriminator_hex {
|
||||
Some(discriminator_hex) => discriminator_hex,
|
||||
None => continue,
|
||||
};
|
||||
let discriminator_len = match discriminator_len_usize(entry.discriminator_len) {
|
||||
Some(discriminator_len) => discriminator_len,
|
||||
None => continue,
|
||||
};
|
||||
if !data_prefix_matches_discriminator(data.as_slice(), discriminator_len, discriminator_hex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if discriminator_len > selected_len {
|
||||
selected_entry = Some(entry);
|
||||
selected_len = discriminator_len;
|
||||
}
|
||||
}
|
||||
let selected_entry = match selected_entry {
|
||||
Some(selected_entry) => selected_entry,
|
||||
None => return None,
|
||||
};
|
||||
return Some(selected_entry.to_dto());
|
||||
}
|
||||
|
||||
fn discriminator_len_usize(
|
||||
discriminator_len: std::option::Option<u16>,
|
||||
) -> std::option::Option<usize> {
|
||||
let discriminator_len = match discriminator_len {
|
||||
Some(discriminator_len) => discriminator_len,
|
||||
None => return None,
|
||||
};
|
||||
if discriminator_len == 0 {
|
||||
return None;
|
||||
}
|
||||
return Some(usize::from(discriminator_len));
|
||||
}
|
||||
|
||||
fn decode_base58_instruction_data(
|
||||
data_base58: std::option::Option<&str>,
|
||||
) -> std::option::Option<std::vec::Vec<u8>> {
|
||||
let data_base58 = match data_base58 {
|
||||
Some(data_base58) => data_base58.trim(),
|
||||
None => return None,
|
||||
};
|
||||
if data_base58.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let decoded_result = bs58::decode(data_base58).into_vec();
|
||||
match decoded_result {
|
||||
Ok(decoded) => return Some(decoded),
|
||||
Err(_) => return None,
|
||||
}
|
||||
}
|
||||
|
||||
fn data_prefix_matches_discriminator(
|
||||
data: &[u8],
|
||||
discriminator_len: usize,
|
||||
discriminator_hex: &str,
|
||||
) -> bool {
|
||||
if data.len() < discriminator_len {
|
||||
return false;
|
||||
}
|
||||
let data_prefix_hex = bytes_prefix_to_hex(data, discriminator_len);
|
||||
return data_prefix_hex == discriminator_hex;
|
||||
}
|
||||
|
||||
fn bytes_prefix_to_hex(data: &[u8], len: usize) -> std::string::String {
|
||||
let mut text = std::string::String::new();
|
||||
let mut index = 0_usize;
|
||||
while index < len {
|
||||
let byte = data[index];
|
||||
text.push_str(format!("{byte:02x}").as_str());
|
||||
index += 1;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[test]
|
||||
fn registry_contains_openbook_v2_idl_instruction_discriminators_without_local_verification() {
|
||||
let expected = [
|
||||
("create_market", "67e261ebc8bcfbfe"),
|
||||
("close_market", "589af8ba300e7bf4"),
|
||||
("create_open_orders_account", "ccb5afde287dbc47"),
|
||||
("close_open_orders_account", "b04a73d236b35b67"),
|
||||
("place_order", "33c29baf6d82606a"),
|
||||
("place_take_order", "032c47031ac7cb55"),
|
||||
("consume_events", "dd91b1341f2f3fc9"),
|
||||
("consume_given_events", "d1e336046dac2947"),
|
||||
("cancel_order", "5f81edf00831df84"),
|
||||
("cancel_order_by_client_order_id", "73b2c908afb77b77"),
|
||||
("cancel_all_orders", "c453f3ab1164a08f"),
|
||||
("deposit", "f223c68952e1f2b6"),
|
||||
("settle_funds", "ee40a3604bab1021"),
|
||||
("sweep_fees", "afe1624776422294"),
|
||||
];
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
for (entry_name, discriminator_hex) in expected {
|
||||
let mut found = false;
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.decoder_code == "openbook-v2"
|
||||
&& entry.program_id.as_deref() == Some(crate::OPENBOOK_V2_PROGRAM_ID)
|
||||
&& entry.entry_kind == crate::ENTRY_KIND_INSTRUCTION
|
||||
&& entry.entry_name == entry_name
|
||||
&& entry.discriminator_hex.as_deref() == Some(discriminator_hex)
|
||||
&& entry.discriminator_len == Some(8)
|
||||
&& entry.proof_status == crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
found,
|
||||
"missing OpenBook v2 discriminator entry '{}', '{}'",
|
||||
entry_name, discriminator_hex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openbook_v2_place_take_order_discriminator_matches_raw_data() {
|
||||
let data =
|
||||
bs58::encode([3_u8, 44_u8, 71_u8, 3_u8, 26_u8, 199_u8, 203_u8, 85_u8]).into_string();
|
||||
let matched = crate::upstream_registry_match::upstream_registry_match_instruction_data(
|
||||
crate::OPENBOOK_V2_PROGRAM_ID,
|
||||
Some(data.as_str()),
|
||||
);
|
||||
let matched = match matched {
|
||||
Some(matched) => matched,
|
||||
None => panic!("OpenBook v2 place_take_order discriminator must match"),
|
||||
};
|
||||
assert_eq!(matched.decoder_code, "openbook-v2".to_string());
|
||||
assert_eq!(matched.entry_name, "place_take_order".to_string());
|
||||
assert_eq!(matched.discriminator_hex, Some("032c47031ac7cb55".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_contains_priority_family_program_seeds() {
|
||||
let expected_codes = [
|
||||
"meteora-damm-v2",
|
||||
"meteora-dbc",
|
||||
"meteora-dlmm",
|
||||
"meteora-vault",
|
||||
"raydium-amm-v4",
|
||||
"raydium-clmm",
|
||||
"raydium-cpmm",
|
||||
"raydium-launchpad",
|
||||
"raydium-liquidity-locking",
|
||||
"raydium-stable-swap",
|
||||
"orca-whirlpool",
|
||||
"fluxbeam",
|
||||
"lifinity-amm-v2",
|
||||
"phoenix-v1",
|
||||
"openbook-v2",
|
||||
"stabble-stable-swap",
|
||||
"stabble-weighted-swap",
|
||||
"bonkswap",
|
||||
"boop",
|
||||
"moonshot",
|
||||
"heaven",
|
||||
"okx-dex",
|
||||
"pancake-swap",
|
||||
"vertigo",
|
||||
"virtuals",
|
||||
"wavebreak",
|
||||
"onchain-labs-dex-v1",
|
||||
"onchain-labs-dex-v2",
|
||||
"jupiter-swap",
|
||||
"jupiter-dca",
|
||||
"jupiter-limit-order",
|
||||
"jupiter-limit-order-2",
|
||||
"jupiter-perpetuals",
|
||||
"jupiter-lend",
|
||||
"kamino-lending",
|
||||
"kamino-vault",
|
||||
"kamino-farms",
|
||||
"kamino-limit-order",
|
||||
"drift-v2",
|
||||
"marginfi-v2",
|
||||
"dflow-aggregator-v4",
|
||||
"zeta",
|
||||
"system-program",
|
||||
"token-program",
|
||||
"token-2022",
|
||||
"associated-token-account",
|
||||
"address-lookup-table",
|
||||
"memo-program",
|
||||
"stake-program",
|
||||
"mpl-token-metadata",
|
||||
"mpl-core",
|
||||
"bubblegum",
|
||||
"name-service",
|
||||
"marinade-finance",
|
||||
"solayer-restaking-program",
|
||||
"swig",
|
||||
"sharky",
|
||||
"circle-message-transmitter-v2",
|
||||
"circle-token-messenger-v2",
|
||||
];
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
for expected_code in expected_codes {
|
||||
let mut found = false;
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.decoder_code == expected_code
|
||||
&& entry.entry_kind == crate::ENTRY_KIND_PROGRAM
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(found, "missing upstream registry code '{}'", expected_code);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_has_no_duplicate_entry_keys() {
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for entry in all_entries.as_slice() {
|
||||
let key = (
|
||||
entry.decoder_code.as_str(),
|
||||
entry.program_id.as_deref(),
|
||||
entry.entry_kind.as_str(),
|
||||
entry.entry_name.as_str(),
|
||||
entry.discriminator_hex.as_deref(),
|
||||
);
|
||||
assert!(
|
||||
seen.insert(key),
|
||||
"duplicate upstream registry entry: decoder={} program_id={:?} kind={} name={} discriminator={:?}",
|
||||
entry.decoder_code,
|
||||
entry.program_id,
|
||||
entry.entry_kind,
|
||||
entry.entry_name,
|
||||
entry.discriminator_hex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_has_no_duplicate_program_entry_for_same_decoder_and_program_id() {
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.entry_kind != crate::ENTRY_KIND_PROGRAM {
|
||||
continue;
|
||||
}
|
||||
let key = (entry.decoder_code.as_str(), entry.program_id.as_deref());
|
||||
assert!(
|
||||
seen.insert(key),
|
||||
"duplicate upstream registry program entry: decoder={} program_id={:?}",
|
||||
entry.decoder_code,
|
||||
entry.program_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_has_no_duplicate_program_id_for_program_rows() {
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
let mut seen = std::collections::BTreeMap::<&str, &str>::new();
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.entry_kind != crate::ENTRY_KIND_PROGRAM {
|
||||
continue;
|
||||
}
|
||||
let program_id = match entry.program_id.as_deref() {
|
||||
Some(program_id) => program_id,
|
||||
None => continue,
|
||||
};
|
||||
match seen.insert(program_id, entry.decoder_code.as_str()) {
|
||||
Some(previous_decoder) => panic!(
|
||||
"duplicate upstream registry program_id {} for {} and {}",
|
||||
program_id, previous_decoder, entry.decoder_code
|
||||
),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_has_no_duplicate_program_discriminator_keys() {
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.entry_kind == crate::ENTRY_KIND_PROGRAM {
|
||||
continue;
|
||||
}
|
||||
let program_id = match entry.program_id.as_deref() {
|
||||
Some(program_id) => program_id,
|
||||
None => continue,
|
||||
};
|
||||
let discriminator_hex = match entry.discriminator_hex.as_deref() {
|
||||
Some(discriminator_hex) => discriminator_hex,
|
||||
None => continue,
|
||||
};
|
||||
let key = (
|
||||
program_id,
|
||||
entry.entry_kind.as_str(),
|
||||
entry.entry_name.as_str(),
|
||||
discriminator_hex,
|
||||
);
|
||||
assert!(
|
||||
seen.insert(key),
|
||||
"duplicate upstream registry discriminator key: program_id={} kind={} name={} discriminator={}",
|
||||
program_id,
|
||||
entry.entry_kind,
|
||||
entry.entry_name,
|
||||
discriminator_hex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_does_not_claim_local_corpus_verification_in_bootstrap_tranche() {
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
for entry in all_entries.as_slice() {
|
||||
assert_eq!(entry.proof_status, crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED);
|
||||
assert_ne!(entry.proof_status, crate::PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_OBSERVED);
|
||||
assert_ne!(
|
||||
entry.proof_status,
|
||||
crate::PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_MATERIALIZED
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_contains_all_meteora_damm_v2_instruction_discriminators_without_local_verification()
|
||||
{
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
let expected_entries = [
|
||||
("add_liquidity", "b59d59438fb63448"),
|
||||
("claim_partner_fee", "61ce27695e5e7e94"),
|
||||
("claim_position_fee", "b4269a118521a2d3"),
|
||||
("claim_protocol_fee", "a5e4853063f9ff21"),
|
||||
("claim_reward", "955fb5f25e5a9ea2"),
|
||||
("cpi_event", "bcd8a66c1aa68eb6"),
|
||||
("initialize_pool", "5fb40aac54aee828"),
|
||||
("remove_liquidity", "5055d14818ceb16c"),
|
||||
("swap", "f8c69e91e17587c8"),
|
||||
("swap2", "414b3f4ceb5b5b88"),
|
||||
("update_pool_fees", "76d9cbb33c084659"),
|
||||
("withdraw_ineligible_reward", "94ce2ac3f7316708"),
|
||||
];
|
||||
|
||||
for expected_entry in expected_entries {
|
||||
let mut found = false;
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.decoder_code == "meteora-damm-v2"
|
||||
&& entry.entry_kind == crate::ENTRY_KIND_INSTRUCTION
|
||||
&& entry.entry_name == expected_entry.0
|
||||
&& entry.discriminator_hex.as_deref() == Some(expected_entry.1)
|
||||
&& entry.discriminator_len == Some(8)
|
||||
&& entry.proof_status == crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
found,
|
||||
"missing upstream Git discriminator entry '{}', '{}'",
|
||||
expected_entry.0, expected_entry.1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_contains_meteora_damm_v2_event_discriminators_without_local_verification() {
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
let expected_entries =
|
||||
[("evt_liquidity_change", "c5ab4e7fe0d3570d"), ("evt_swap2", "bd4233a826507599")];
|
||||
|
||||
for expected_entry in expected_entries {
|
||||
let mut found = false;
|
||||
for entry in all_entries.as_slice() {
|
||||
if entry.decoder_code == "meteora-damm-v2"
|
||||
&& entry.entry_kind == crate::ENTRY_KIND_EVENT
|
||||
&& entry.entry_name == expected_entry.0
|
||||
&& entry.discriminator_hex.as_deref() == Some(expected_entry.1)
|
||||
&& entry.discriminator_len == Some(8)
|
||||
&& entry.proof_status == crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(found, "missing upstream Git event entry '{}'", expected_entry.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_anchor_instruction_data_by_program_id_and_discriminator() {
|
||||
let data =
|
||||
[0xb5_u8, 0x9d_u8, 0x59_u8, 0x43_u8, 0x8f_u8, 0xb6_u8, 0x34_u8, 0x48_u8, 0x01_u8];
|
||||
let data_base58 = bs58::encode(data).into_string();
|
||||
let matched = crate::upstream_registry_match::upstream_registry_match_instruction_data(
|
||||
crate::METEORA_DAMM_V2_PROGRAM_ID,
|
||||
Some(data_base58.as_str()),
|
||||
);
|
||||
let matched = match matched {
|
||||
Some(matched) => matched,
|
||||
None => panic!("missing meteora-damm-v2 add_liquidity registry match"),
|
||||
};
|
||||
assert_eq!(matched.decoder_code, "meteora-damm-v2");
|
||||
assert_eq!(matched.entry_name, "add_liquidity");
|
||||
assert_eq!(matched.discriminator_hex.as_deref(), Some("b59d59438fb63448"));
|
||||
assert_eq!(matched.proof_status, crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_one_byte_instruction_data_by_program_id_and_discriminator() {
|
||||
let data = [0x00_u8, 0x10_u8, 0x20_u8];
|
||||
let data_base58 = bs58::encode(data).into_string();
|
||||
let matched = crate::upstream_registry_match::upstream_registry_match_instruction_data(
|
||||
crate::PHOENIX_V1_PROGRAM_ID,
|
||||
Some(data_base58.as_str()),
|
||||
);
|
||||
let matched = match matched {
|
||||
Some(matched) => matched,
|
||||
None => panic!("missing phoenix-v1 swap registry match"),
|
||||
};
|
||||
assert_eq!(matched.decoder_code, "phoenix-v1");
|
||||
assert_eq!(matched.entry_name, "swap");
|
||||
assert_eq!(matched.discriminator_hex.as_deref(), Some("00"));
|
||||
assert_eq!(matched.discriminator_len, Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_can_filter_by_program_id_and_family() {
|
||||
let request = crate::UpstreamRegistrySearchRequestDto {
|
||||
decoder_code: None,
|
||||
program_id: Some(crate::RAYDIUM_CPMM_PROGRAM_ID.to_string()),
|
||||
program_family: Some("raydium".to_string()),
|
||||
surface_kind: None,
|
||||
entry_kind: None,
|
||||
proof_status: None,
|
||||
limit: None,
|
||||
};
|
||||
let result = crate::upstream_registry_match::upstream_registry_search(&request);
|
||||
assert!(result.entries.len() >= 2);
|
||||
for entry in result.entries.as_slice() {
|
||||
assert_eq!(entry.decoder_code, "raydium-cpmm");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_uses_generic_upstream_git_status_names_only() {
|
||||
let deprecated_external_repo_prefix = format!("{}{}", "car", "bon");
|
||||
let forbidden_terms = [deprecated_external_repo_prefix];
|
||||
let all_entries = crate::upstream_registry_match::upstream_registry_all_entries();
|
||||
for entry in all_entries.as_slice() {
|
||||
let payload = format!(
|
||||
"{} {} {} {} {}",
|
||||
entry.decoder_code,
|
||||
entry.program_family,
|
||||
entry.surface_kind,
|
||||
entry.proof_status,
|
||||
entry.notes
|
||||
);
|
||||
for forbidden_term in forbidden_terms.as_slice() {
|
||||
assert!(
|
||||
!payload.to_ascii_lowercase().contains(forbidden_term.as_str()),
|
||||
"forbidden registry term found: {}",
|
||||
forbidden_term
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
177
kb_lib/src/upstream_registry_types.rs
Normal file
177
kb_lib/src/upstream_registry_types.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
// file: kb_lib/src/upstream_registry_types.rs
|
||||
|
||||
//! Shared DTOs and static-entry types for the upstream Git registry.
|
||||
//!
|
||||
//! The registry is a discovery index. It must not be interpreted as local
|
||||
//! business proof that a DEX, instruction, event, trade, metric or candle has
|
||||
//! been validated against the current SQLite corpus.
|
||||
|
||||
/// Registry entry kind for an instruction discriminator.
|
||||
pub const ENTRY_KIND_INSTRUCTION: &str = "instruction";
|
||||
/// Registry entry kind for an emitted event discriminator.
|
||||
pub const ENTRY_KIND_EVENT: &str = "event";
|
||||
/// Registry entry kind for an account discriminator or account layout.
|
||||
pub const ENTRY_KIND_ACCOUNT: &str = "account";
|
||||
/// Registry entry kind for a program-level seed row.
|
||||
pub const ENTRY_KIND_PROGRAM: &str = "program";
|
||||
|
||||
/// Generic protocol name used for upstream registry matches that are not business-materialized.
|
||||
pub const UPSTREAM_REGISTRY_PROTOCOL_NAME: &str = "upstream_git";
|
||||
/// Generic event kind used for instruction-level upstream registry matches.
|
||||
pub const UPSTREAM_REGISTRY_INSTRUCTION_MATCH_EVENT_KIND: &str = "upstream_git.instruction_match";
|
||||
|
||||
/// Generic upstream Git status for an entry that has not been observed locally.
|
||||
pub const PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED: &str = "upstream_git_unverified";
|
||||
/// Generic upstream Git status for an entry wired into a decoder but not observed locally.
|
||||
pub const PROOF_STATUS_UPSTREAM_GIT_MAPPED_UNVERIFIED: &str = "upstream_git_mapped_unverified";
|
||||
/// Generic upstream Git status for an entry observed in the local corpus.
|
||||
pub const PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_OBSERVED: &str =
|
||||
"upstream_git_local_corpus_observed";
|
||||
/// Generic upstream Git status for an entry materialized in local business tables.
|
||||
pub const PROOF_STATUS_UPSTREAM_GIT_LOCAL_CORPUS_MATERIALIZED: &str =
|
||||
"upstream_git_local_corpus_materialized";
|
||||
/// Generic upstream Git status for a known layout that is not yet locally validated.
|
||||
pub const PROOF_STATUS_UPSTREAM_GIT_LAYOUT_UNVERIFIED: &str = "upstream_git_layout_unverified";
|
||||
|
||||
/// Static registry entry used by generated or hand-curated bootstrap data.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct UpstreamRegistryEntry {
|
||||
/// Repository name or bootstrap locator that produced the entry.
|
||||
pub source_repo: std::option::Option<&'static str>,
|
||||
/// Repository-relative path or bootstrap path that produced the entry.
|
||||
pub source_path: std::option::Option<&'static str>,
|
||||
/// Stable decoder code used by the registry.
|
||||
pub decoder_code: &'static str,
|
||||
/// Optional Solana program id when already known by the source entry.
|
||||
pub program_id: std::option::Option<&'static str>,
|
||||
/// Program family used to group related programs.
|
||||
pub program_family: &'static str,
|
||||
/// Surface kind such as AMM, CLMM, launch, aggregator or core Solana.
|
||||
pub surface_kind: &'static str,
|
||||
/// Entry kind: instruction, event, account or program.
|
||||
pub entry_kind: &'static str,
|
||||
/// Source-level entry name.
|
||||
pub entry_name: &'static str,
|
||||
/// Optional discriminator bytes encoded as lowercase hexadecimal.
|
||||
pub discriminator_hex: std::option::Option<&'static str>,
|
||||
/// Optional discriminator byte length.
|
||||
pub discriminator_len: std::option::Option<u16>,
|
||||
/// Current proof status.
|
||||
pub proof_status: &'static str,
|
||||
/// Notes that preserve uncertainty and validation requirements.
|
||||
pub notes: &'static str,
|
||||
}
|
||||
|
||||
impl UpstreamRegistryEntry {
|
||||
/// Converts a static entry into an owned DTO for application/UI boundaries.
|
||||
pub fn to_dto(&self) -> crate::UpstreamRegistryEntryDto {
|
||||
return crate::UpstreamRegistryEntryDto {
|
||||
source_repo: self.source_repo.map(std::string::ToString::to_string),
|
||||
source_path: self.source_path.map(std::string::ToString::to_string),
|
||||
decoder_code: self.decoder_code.to_string(),
|
||||
program_id: self.program_id.map(std::string::ToString::to_string),
|
||||
program_family: self.program_family.to_string(),
|
||||
surface_kind: self.surface_kind.to_string(),
|
||||
entry_kind: self.entry_kind.to_string(),
|
||||
entry_name: self.entry_name.to_string(),
|
||||
discriminator_hex: self.discriminator_hex.map(std::string::ToString::to_string),
|
||||
discriminator_len: self.discriminator_len,
|
||||
proof_status: self.proof_status.to_string(),
|
||||
notes: self.notes.to_string(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Owned registry entry DTO exposed at crate and UI boundaries.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpstreamRegistryEntryDto {
|
||||
/// Repository name or bootstrap locator that produced the entry.
|
||||
pub source_repo: std::option::Option<std::string::String>,
|
||||
/// Repository-relative path or bootstrap path that produced the entry.
|
||||
pub source_path: std::option::Option<std::string::String>,
|
||||
/// Stable decoder code used by the registry.
|
||||
pub decoder_code: std::string::String,
|
||||
/// Optional Solana program id when already known by the source entry.
|
||||
pub program_id: std::option::Option<std::string::String>,
|
||||
/// Program family used to group related programs.
|
||||
pub program_family: std::string::String,
|
||||
/// Surface kind such as AMM, CLMM, launch, aggregator or core Solana.
|
||||
pub surface_kind: std::string::String,
|
||||
/// Entry kind: instruction, event, account or program.
|
||||
pub entry_kind: std::string::String,
|
||||
/// Source-level entry name.
|
||||
pub entry_name: std::string::String,
|
||||
/// Optional discriminator bytes encoded as lowercase hexadecimal.
|
||||
pub discriminator_hex: std::option::Option<std::string::String>,
|
||||
/// Optional discriminator byte length.
|
||||
pub discriminator_len: std::option::Option<u16>,
|
||||
/// Current proof status.
|
||||
pub proof_status: std::string::String,
|
||||
/// Notes that preserve uncertainty and validation requirements.
|
||||
pub notes: std::string::String,
|
||||
}
|
||||
|
||||
/// Search/filter request for registry entries.
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpstreamRegistrySearchRequestDto {
|
||||
/// Optional decoder-code filter.
|
||||
pub decoder_code: std::option::Option<std::string::String>,
|
||||
/// Optional program-id filter.
|
||||
pub program_id: std::option::Option<std::string::String>,
|
||||
/// Optional program-family filter.
|
||||
pub program_family: std::option::Option<std::string::String>,
|
||||
/// Optional surface-kind filter.
|
||||
pub surface_kind: std::option::Option<std::string::String>,
|
||||
/// Optional entry-kind filter.
|
||||
pub entry_kind: std::option::Option<std::string::String>,
|
||||
/// Optional proof-status filter.
|
||||
pub proof_status: std::option::Option<std::string::String>,
|
||||
/// Optional maximum number of returned entries.
|
||||
pub limit: std::option::Option<usize>,
|
||||
}
|
||||
|
||||
/// Summary of the current registry snapshot.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpstreamRegistrySummaryDto {
|
||||
/// Total static registry entry count before filtering.
|
||||
pub total_entry_count: usize,
|
||||
/// Returned entry count after filtering.
|
||||
pub returned_entry_count: usize,
|
||||
/// Number of entries that have a program id.
|
||||
pub entries_with_program_id_count: usize,
|
||||
/// Number of entries that have a discriminator.
|
||||
pub entries_with_discriminator_count: usize,
|
||||
/// Number of program-level seed entries.
|
||||
pub program_entry_count: usize,
|
||||
/// Number of instruction entries.
|
||||
pub instruction_entry_count: usize,
|
||||
/// Number of event entries.
|
||||
pub event_entry_count: usize,
|
||||
/// Number of account entries.
|
||||
pub account_entry_count: usize,
|
||||
/// Number of entries still unverified from upstream Git or seed data.
|
||||
pub upstream_git_unverified_count: usize,
|
||||
/// Number of entries mapped into decoders but not locally observed.
|
||||
pub upstream_git_mapped_unverified_count: usize,
|
||||
/// Number of entries observed in the local corpus.
|
||||
pub upstream_git_local_corpus_observed_count: usize,
|
||||
/// Number of entries materialized in local business tables.
|
||||
pub upstream_git_local_corpus_materialized_count: usize,
|
||||
/// Number of layout entries still unverified locally.
|
||||
pub upstream_git_layout_unverified_count: usize,
|
||||
}
|
||||
|
||||
/// Search result returned by the upstream registry service.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpstreamRegistrySearchResultDto {
|
||||
/// Normalized request used for the search.
|
||||
pub request: crate::UpstreamRegistrySearchRequestDto,
|
||||
/// Registry summary.
|
||||
pub summary: crate::UpstreamRegistrySummaryDto,
|
||||
/// Matching entries.
|
||||
pub entries: std::vec::Vec<crate::UpstreamRegistryEntryDto>,
|
||||
}
|
||||
Reference in New Issue
Block a user