0.7.47-1FE5

This commit is contained in:
2026-05-31 16:43:19 +02:00
parent 7bd6593015
commit 8b09e82b3b
39 changed files with 24260 additions and 332 deletions

View File

@@ -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

View File

@@ -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;

File diff suppressed because it is too large Load Diff

1325
kb_lib/src/dex/phoenix_v1.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -124,7 +124,6 @@ mod tests {
fn planned_launch_surfaces_are_present_but_disabled() {
let codes = [
"raydium_launchlab",
"raydium_launchpad",
"letsbonk",
"boop_fun",
"moonshot",

View File

@@ -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,
&registry_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,
&registry_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)
);
}
}

View File

@@ -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

View File

@@ -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;
return false;
}
if decoded_event.token_a_mint.is_none() {
return true;
return false;
}
if decoded_event.token_b_mint.is_none() {
return true;
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
));
}
return false;
}

View File

@@ -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

View File

@@ -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",

View File

@@ -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.

View File

@@ -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

View 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());
}
}

File diff suppressed because it is too large Load Diff

View 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
);
}
}
}
}

View 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>,
}