This commit is contained in:
2026-06-08 12:32:58 +02:00
parent f81e0f3bea
commit f2ea1a392f
55 changed files with 7993 additions and 306 deletions

View File

@@ -276,7 +276,13 @@ pub const RAYDIUM_CLMM_PROGRAM_ID: &str = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7gr
pub const RAYDIUM_CPMM_PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
/// Raydium LaunchLab / Launchpad program id. ("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj").
pub const RAYDIUM_LAUNCHLAB_PROGRAM_ID: &str = "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj";
pub const RAYDIUM_LAUNCHPAD_PROGRAM_ID: &str = "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj";
/// Raydium LaunchLab platform config account observed on Solscan.
///
/// This is an account source, not a decoder program id.
pub const RAYDIUM_LAUNCHPAD_PLATFORM_CONFIG_ACCOUNT_ID: &str =
"4Bu96XjU84XjPDSpveTVf6LYGCkfW5FK7SNkREWcEfV4";
/// Raydium AMM routing program id. ("routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS").
pub const RAYDIUM_AMM_ROUTING_PROGRAM_ID: &str = "routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS";
@@ -341,9 +347,14 @@ pub const MARINADE_FINANCE_PROGRAM_ID: &str = "MarBmsSgKXdrN1egZf5sqe1TMai9K1rCh
/// 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.
/// Moonshot program id kept for upstream `moonshot` decoder compatibility.
///
/// Moonit / Moonshot-family program id observed with a Solscan Program IDL.
pub const MOONSHOT_PROGRAM_ID: &str = "MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG";
/// Moonshot token authority account observed on Solscan, not a decoder program.
pub const MOONSHOT_TOKEN_AUTHORITY_ID: &str = "7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q";
/// OKX DEX program id extracted from upstream Git decoder source.
pub const OKX_DEX_PROGRAM_ID: &str = "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma";
@@ -415,3 +426,953 @@ pub const NAME_SERVICE_PROGRAM_ID: &str = "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8
/// This is not treated as a DEX program. It is used only to tag protocol
/// candidates with `candidate_surface = "arbitrage_bot"`.
pub const ARBITRAGE_BOT_6MWVT_PROGRAM_ID: &str = "6MWVTis8rmmk6Vt9zmAJJbmb3VuLpzoQ1aHH4N6wQEGh";
/// One Solscan account source collected during manual DEX/program inventory.
///
/// This catalogue is intentionally broader than supported DEXes: it also contains
/// routers, token authorities, bot programs, lending programs and system programs.
/// Promotion into a decoder/support-matrix entry still requires source review and
/// local corpus verification.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SolscanAccountSource {
/// Human-readable label used in the manual source inventory.
pub label: &'static str,
/// Solana account or program id shown by Solscan.
pub account_id: &'static str,
/// Solscan account URL used as the discovery source.
pub solscan_url: &'static str,
/// IDL status observed in the manual Solscan pass.
///
/// Values currently used: `solscan_program_idl`, `no_idl`, `solscan_account`.
pub idl_status: &'static str,
}
/// Manual Solscan account-source inventory collected for post-`0.7.50` DEX discovery.
///
/// This is a source catalogue only. It must not be interpreted as decoder support.
pub const SOLSCAN_ACCOUNT_SOURCES: &[SolscanAccountSource] = &[
SolscanAccountSource {
label: "1Dex Program",
account_id: "DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm",
solscan_url: "https://solscan.io/account/DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "AlphaQ",
account_id: "ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA",
solscan_url: "https://solscan.io/account/ALPHAQmeA7bjrVuccPsYPiCvsi428SNwte66Srvs4pHA",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Aldrin AMM",
account_id: "AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6",
solscan_url: "https://solscan.io/account/AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Aldrin AMM V2",
account_id: "CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4",
solscan_url: "https://solscan.io/account/CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "ApePro Smart Wallet Program",
account_id: "JSW99DKmxNyREQM14SQLDykeBvEUG63TeohrvmofEiw",
solscan_url: "https://solscan.io/account/JSW99DKmxNyREQM14SQLDykeBvEUG63TeohrvmofEiw#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Aquifer",
account_id: "AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45",
solscan_url: "https://solscan.io/account/AQU1FRd7papthgdrwPTTq5JacJh8YtwEXaBfKU3bTz45",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Arbitrage Bot (3s1rA)",
account_id: "3s1rAymURnacreXreMy718GfqW6kygQsLNka1xDyW8pC",
solscan_url: "https://solscan.io/account/3s1rAymURnacreXreMy718GfqW6kygQsLNka1xDyW8pC",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Arbitrage Bot (6MWVT)",
account_id: "6MWVTis8rmmk6Vt9zmAJJbmb3VuLpzoQ1aHH4N6wQEGh",
solscan_url: "https://solscan.io/account/6MWVTis8rmmk6Vt9zmAJJbmb3VuLpzoQ1aHH4N6wQEGh",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Arbitrage Bot (9Zzf9)",
account_id: "9Zzf9QqTy3TkyXysvJBsXyuRjda5aXCEJ9vXfL2HKSYv",
solscan_url: "https://solscan.io/account/9Zzf9QqTy3TkyXysvJBsXyuRjda5aXCEJ9vXfL2HKSYv",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Axiom Trade",
account_id: "FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9",
solscan_url: "https://solscan.io/account/FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Bags: Token Authority",
account_id: "BAGSB9TpGrZxQbEsrEznv5jXXdwyP6AXerN8aVRiAmcv",
solscan_url: "https://solscan.io/account/BAGSB9TpGrZxQbEsrEznv5jXXdwyP6AXerN8aVRiAmcv",
idl_status: "solscan_account",
},
SolscanAccountSource {
label: "Believe : Token Authority",
account_id: "5qWya6UjwWnGVhdSBL3hyZ7B45jbk6Byt1hwd7ohEGXE",
solscan_url: "https://solscan.io/account/5qWya6UjwWnGVhdSBL3hyZ7B45jbk6Byt1hwd7ohEGXE",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "BisonFi",
account_id: "BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi",
solscan_url: "https://solscan.io/account/BiSoNHVpsVZW2F7rx2eQ59yQwKxzU5NvBcmKshCSUypi",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "BonkSwap",
account_id: "BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p",
solscan_url: "https://solscan.io/account/BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Boop.fun",
account_id: "boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4",
solscan_url: "https://solscan.io/account/boop8hVGQGqehUK2iVEMEnMrL5RbjywRzHKBmBE7ry4#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Byreal: CLMM",
account_id: "REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2",
solscan_url: "https://solscan.io/account/REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Bubblegum",
account_id: "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY",
solscan_url: "https://solscan.io/account/BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Carrot DeFi",
account_id: "CarrotwivhMpDnm27EHmRLeQ683Z1PufuqEmBZvD282s",
solscan_url: "https://solscan.io/account/CarrotwivhMpDnm27EHmRLeQ683Z1PufuqEmBZvD282s#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "CCTP TokenMessengerMinter",
account_id: "CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3",
solscan_url: "https://solscan.io/account/CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "CCTP TokenMessengerMinterV2",
account_id: "CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe",
solscan_url: "https://solscan.io/account/CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Clone",
account_id: "C1onEW2kPetmHmwe74YC1ESx3LnFEpVau6g2pg4fHycr",
solscan_url: "https://solscan.io/account/C1onEW2kPetmHmwe74YC1ESx3LnFEpVau6g2pg4fHycr#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Crema Finance Program",
account_id: "CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR",
solscan_url: "https://solscan.io/account/CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Cropper Finance",
account_id: "CTMAxxk34HjKWxQ3QLZK1HpaLXmBveao3ESePXbiyfzh",
solscan_url: "https://solscan.io/account/CTMAxxk34HjKWxQ3QLZK1HpaLXmBveao3ESePXbiyfzh",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Cropper Whirlpool",
account_id: "H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt",
solscan_url: "https://solscan.io/account/H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "deBridge Destination",
account_id: "dst5MGcFPoBeREFAA5E3tU5ij8m5uVYwkzkSAbsLbNo",
solscan_url: "https://solscan.io/account/dst5MGcFPoBeREFAA5E3tU5ij8m5uVYwkzkSAbsLbNo",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "deBridge Source",
account_id: "src5qyZHqTqecJV4aY6Cb6zDZLMDzrDKKezs22MPHr4",
solscan_url: "https://solscan.io/account/src5qyZHqTqecJV4aY6Cb6zDZLMDzrDKKezs22MPHr4",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Dexlab Swap",
account_id: "DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N",
solscan_url: "https://solscan.io/account/DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "DFlow Aggregator v4",
account_id: "DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH",
solscan_url: "https://solscan.io/account/DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Drift V2 Program",
account_id: "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH",
solscan_url: "https://solscan.io/account/dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Fluxbeam Program",
account_id: "FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X",
solscan_url: "https://solscan.io/account/FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Fusion AMM",
account_id: "fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9",
solscan_url: "https://solscan.io/account/fUSioN9YKKSa3CUC2YUc4tPkHJ5Y6XW1yz8y6F7qWz9#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Futarchy AMM",
account_id: "FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq",
solscan_url: "https://solscan.io/account/FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Gavel",
account_id: "srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi",
solscan_url: "https://solscan.io/account/srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "GoonFi",
account_id: "goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j",
solscan_url: "https://solscan.io/account/goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "GoonFi V2",
account_id: "goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE",
solscan_url: "https://solscan.io/account/goonuddtQRrWqqn5nFyczVKaie28f3kDkHWkHtURSLE",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "GooseFX: GAMMA",
account_id: "GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT",
solscan_url: "https://solscan.io/account/GAMMA7meSFWaBXF25oSUgmGRwaW6sCMFLmBNiMSdbHVT#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "GooseFX V2",
account_id: "GFXsSL5sSaDfNFQUYsHekbWBW1TsFdjDYzACh62tEHxn",
solscan_url: "https://solscan.io/account/GFXsSL5sSaDfNFQUYsHekbWBW1TsFdjDYzACh62tEHxn#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Guac Swap",
account_id: "Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1",
solscan_url: "https://solscan.io/account/Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "HawkFi Program",
account_id: "FqGg2Y1FNxMiGd51Q6UETixQWkF5fB92MysbYogRJb3P",
solscan_url: "https://solscan.io/account/FqGg2Y1FNxMiGd51Q6UETixQWkF5fB92MysbYogRJb3P",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Heaven DEX",
account_id: "HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o",
solscan_url: "https://solscan.io/account/HEAVENoP2qxoeuF8Dj2oT1GHEnu49U5mJYkdeC8BAX2o",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Helium Treasury Management",
account_id: "treaf4wWBBty3fHdyBpo35Mz84M8k3heKXmjmi9vFt5",
solscan_url: "https://solscan.io/account/treaf4wWBBty3fHdyBpo35Mz84M8k3heKXmjmi9vFt5#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "HumidiFi",
account_id: "9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp",
solscan_url: "https://solscan.io/account/9H6tua7jkLhdm3w8BvgpTn5LZNU7g4ZynDmCiNN3q6Rp",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Hylo Exchange",
account_id: "HYEXCHtHkBagdStcJCp3xbbb9B7sdMdWXFNj6mdsG4hn",
solscan_url: "https://solscan.io/account/HYEXCHtHkBagdStcJCp3xbbb9B7sdMdWXFNj6mdsG4hn#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Hylo Stability Pool",
account_id: "HysTabVUfmQBFcmzu1ctRd1Y1fxd66RBpboy1bmtDSQQ",
solscan_url: "https://solscan.io/account/HysTabVUfmQBFcmzu1ctRd1Y1fxd66RBpboy1bmtDSQQ#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Invariant Swap",
account_id: "HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt",
solscan_url: "https://solscan.io/account/HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Jito Tip Distribution",
account_id: "4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7",
solscan_url: "https://solscan.io/account/4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Aggregator v6",
account_id: "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
solscan_url: "https://solscan.io/account/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Aggregator v4",
account_id: "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB",
solscan_url: "https://solscan.io/account/JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter DCA program",
account_id: "DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M",
solscan_url: "https://solscan.io/account/DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Lend Borrow",
account_id: "jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi",
solscan_url: "https://solscan.io/account/jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Jupiter Lend Earn",
account_id: "jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9",
solscan_url: "https://solscan.io/account/jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Lend Flash Loan",
account_id: "jupgfSgfuAXv4B6R2Uxu85Z1qdzgju79s6MfZekN6XS",
solscan_url: "https://solscan.io/account/jupgfSgfuAXv4B6R2Uxu85Z1qdzgju79s6MfZekN6XS",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Jupiter Lend Liquidity",
account_id: "jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC",
solscan_url: "https://solscan.io/account/jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Jupiter Limit Order",
account_id: "jupoNjAxXgZ4rjzxzPMP4oxduvQsQtZzyknqvzYNrNu",
solscan_url: "https://solscan.io/account/jupoNjAxXgZ4rjzxzPMP4oxduvQsQtZzyknqvzYNrNu#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Limit Order V2",
account_id: "j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X",
solscan_url: "https://solscan.io/account/j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Lock",
account_id: "LocpQgucEQHbqNABEYvBvwoxCPsSbG91A1QaQhQQqjn",
solscan_url: "https://solscan.io/account/LocpQgucEQHbqNABEYvBvwoxCPsSbG91A1QaQhQQqjn#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Perpetuals",
account_id: "PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu",
solscan_url: "https://solscan.io/account/PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jupiter Prediction Market",
account_id: "3ZZuTbwC6aJbvteyVxXUS7gtFYdf7AuXeitx6VyvjvUp",
solscan_url: "https://solscan.io/account/3ZZuTbwC6aJbvteyVxXUS7gtFYdf7AuXeitx6VyvjvUp",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Jupiter Stable Program",
account_id: "JUPUSDecMzAVgztLe6eGhwUBj1Pn3j9WAXwmtHmfbRr",
solscan_url: "https://solscan.io/account/JUPUSDecMzAVgztLe6eGhwUBj1Pn3j9WAXwmtHmfbRr#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Jup Studio: Authority",
account_id: "8rE9CtCjwhSmbwL5fbJBtRFsS3ohfMcDFeTTC7t4ciUA",
solscan_url: "https://solscan.io/account/8rE9CtCjwhSmbwL5fbJBtRFsS3ohfMcDFeTTC7t4ciUA",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Kamino Program",
account_id: "6LtLpnUFNByNXLyCoK9wA2MykKAmQNZKBdY8s47dehDc",
solscan_url: "https://solscan.io/account/6LtLpnUFNByNXLyCoK9wA2MykKAmQNZKBdY8s47dehDc#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Kamino Lending Program",
account_id: "KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD",
solscan_url: "https://solscan.io/account/KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Kamino Farm",
account_id: "FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr",
solscan_url: "https://solscan.io/account/FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Kamino Vault Program",
account_id: "kvauTFR8qm1dhniz6pYuBZkuene3Hfrs1VQhVRgCNrr",
solscan_url: "https://solscan.io/account/kvauTFR8qm1dhniz6pYuBZkuene3Hfrs1VQhVRgCNrr#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Kvault Program",
account_id: "KvauGMspG5k6rtzrqqn7WNn3oZdyKqLKwK2XWQ8FLjd",
solscan_url: "https://solscan.io/account/KvauGMspG5k6rtzrqqn7WNn3oZdyKqLKwK2XWQ8FLjd#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "LayerZero Endpoint",
account_id: "76y77prsiCMvXMjuoZ5VRrhG5qYBrUMYTE5WgHqgjEn6",
solscan_url: "https://solscan.io/account/76y77prsiCMvXMjuoZ5VRrhG5qYBrUMYTE5WgHqgjEn6#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "LayerZero Executor",
account_id: "6doghB248px58JSSwG4qejQ46kFMW4AMj7vzJnWZHNZn",
solscan_url: "https://solscan.io/account/6doghB248px58JSSwG4qejQ46kFMW4AMj7vzJnWZHNZn#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "letsbonk.fun: PlatformConfig",
account_id: "FfYek5vEz23cMkWsdJwG2oa6EphsvXSHrGpdALN4g6W1",
solscan_url: "https://solscan.io/account/FfYek5vEz23cMkWsdJwG2oa6EphsvXSHrGpdALN4g6W1",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Lifinity Swap",
account_id: "EewxydAPCCVuNEyrVN68PuSYdQ7wKn27V9Gjeoi8dy3S",
solscan_url: "https://solscan.io/account/EewxydAPCCVuNEyrVN68PuSYdQ7wKn27V9Gjeoi8dy3S",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Lifinity Swap V2",
account_id: "2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c",
solscan_url: "https://solscan.io/account/2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Manifest",
account_id: "MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms",
solscan_url: "https://solscan.io/account/MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Marcopolo Swap",
account_id: "9tKE7Mbmj4mxDjWatikzGAtkoWosiiZX9y6J4Hfm2R8H",
solscan_url: "https://solscan.io/account/9tKE7Mbmj4mxDjWatikzGAtkoWosiiZX9y6J4Hfm2R8H",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Marginfi",
account_id: "MFLQPPPPjNinkdKoy2odNFBhvpY43XtCDZjBwG2fwn5",
solscan_url: "https://solscan.io/account/MFLQPPPPjNinkdKoy2odNFBhvpY43XtCDZjBwG2fwn5",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Marginfi V2",
account_id: "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA",
solscan_url: "https://solscan.io/account/MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Marinade Finance",
account_id: "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD",
solscan_url: "https://solscan.io/account/MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Mercurial Stable Swap",
account_id: "MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky",
solscan_url: "https://solscan.io/account/MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "MetaDAO AMM Program v0.5",
account_id: "AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ",
solscan_url: "https://solscan.io/account/AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "MetaDAO Bid Wall Program",
account_id: "WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx",
solscan_url: "https://solscan.io/account/WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "MetaDAO ICO",
account_id: "moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM",
solscan_url: "https://solscan.io/account/moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Metaplex Token Metadata",
account_id: "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
solscan_url: "https://solscan.io/account/metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Meteora DLMM Program",
account_id: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
solscan_url: "https://solscan.io/account/LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Meteora Pools Program",
account_id: "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB",
solscan_url: "https://solscan.io/account/Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Meteora Dynamic Bonding Curve",
account_id: "dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN",
solscan_url: "https://solscan.io/account/dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Meteora DAMM v2",
account_id: "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG",
solscan_url: "https://solscan.io/account/cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Meteora Vault Program",
account_id: "24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi",
solscan_url: "https://solscan.io/account/24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Moonit",
account_id: "MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG",
solscan_url: "https://solscan.io/account/MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Moonshot : Token Authority",
account_id: "7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q",
solscan_url: "https://solscan.io/account/7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Mpl Core",
account_id: "CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d",
solscan_url: "https://solscan.io/account/CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Name Service Program",
account_id: "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX",
solscan_url: "https://solscan.io/account/namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Numeraire",
account_id: "NUMERUNsFCP3kuNmWZuXtm1AaQCPj9uw6Guv2Ekoi5P",
solscan_url: "https://solscan.io/account/NUMERUNsFCP3kuNmWZuXtm1AaQCPj9uw6Guv2Ekoi5P#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Obric V2",
account_id: "obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y",
solscan_url: "https://solscan.io/account/obriQD1zbpyLz95G5n7nJe6a4DPjpFwa5XYPoNm113y",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "OKX Labs 1",
account_id: "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma",
solscan_url: "https://solscan.io/account/6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "OKX: DEX Router",
account_id: "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u",
solscan_url: "https://solscan.io/account/proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Ondo Global Markets",
account_id: "XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm",
solscan_url: "https://solscan.io/account/XzTT4XB8m7sLD2xi6snefSasaswsKCxx5Tifjondogm#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Openbook V2",
account_id: "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb",
solscan_url: "https://solscan.io/account/opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Orca Whirlpools Program",
account_id: "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc",
solscan_url: "https://solscan.io/account/whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Orca Wavebreak",
account_id: "waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF",
solscan_url: "https://solscan.io/account/waveQX2yP3H1pVU8djGvEHmYg8uamQ84AuyGtpsrXTF#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Orca Token Swap",
account_id: "DjVE6JNiYqPL2QXyCUUh8rNjHrbz9hXHNYt99MQ59qw1",
solscan_url: "https://solscan.io/account/DjVE6JNiYqPL2QXyCUUh8rNjHrbz9hXHNYt99MQ59qw1",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Orca Token Swap V2",
account_id: "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP",
solscan_url: "https://solscan.io/account/9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Ore V3 Program",
account_id: "oreV3EG1i9BEgiAJ8b177Z2S2rMarzak4NMv1kULvWv",
solscan_url: "https://solscan.io/account/oreV3EG1i9BEgiAJ8b177Z2S2rMarzak4NMv1kULvWv",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "PancakeSwap",
account_id: "HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq",
solscan_url: "https://solscan.io/account/HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Penguin Finance",
account_id: "PSwapMdSai8tjrEXcxFeQth87xC4rRsa4VA5mhGhXkP",
solscan_url: "https://solscan.io/account/PSwapMdSai8tjrEXcxFeQth87xC4rRsa4VA5mhGhXkP",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Phoenix",
account_id: "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY",
solscan_url: "https://solscan.io/account/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Printr",
account_id: "T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint",
solscan_url: "https://solscan.io/account/T8HsGYv7sMk3kTnyaRqZrbRPuntYzdh12evXBkprint#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Pump.fun",
account_id: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
solscan_url: "https://solscan.io/account/6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Pump.fun AMM",
account_id: "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
solscan_url: "https://solscan.io/account/pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Pump Fees Program",
account_id: "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ",
solscan_url: "https://solscan.io/account/pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "pumpup.ai",
account_id: "PdMDrKEMaX8q7CCJb7NvUCxerBCcsFUa4LjBEynTtEd",
solscan_url: "https://solscan.io/account/PdMDrKEMaX8q7CCJb7NvUCxerBCcsFUa4LjBEynTtEd#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Raydium AMM Routing",
account_id: "routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS",
solscan_url: "https://solscan.io/account/routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Raydium Concentrated Liquidity",
account_id: "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK",
solscan_url: "https://solscan.io/account/CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Raydium CPMM",
account_id: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
solscan_url: "https://solscan.io/account/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Raydium LaunchLab",
account_id: "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj",
solscan_url: "https://solscan.io/account/LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Raydium LaunchLab: PlatformConfig",
account_id: "4Bu96XjU84XjPDSpveTVf6LYGCkfW5FK7SNkREWcEfV4",
solscan_url: "https://solscan.io/account/4Bu96XjU84XjPDSpveTVf6LYGCkfW5FK7SNkREWcEfV4",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Raydium liquidity pool AMM",
account_id: "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h",
solscan_url: "https://solscan.io/account/5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Raydium Liquidity Pool V2",
account_id: "RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr",
solscan_url: "https://solscan.io/account/RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Raydium Liquidity Pool V3",
account_id: "27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv",
solscan_url: "https://solscan.io/account/27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Raydium Liquidity Pool V4",
account_id: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
solscan_url: "https://solscan.io/account/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Raydium Lock LP",
account_id: "LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE",
solscan_url: "https://solscan.io/account/LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Saber Decimal Wrapper",
account_id: "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB",
solscan_url: "https://solscan.io/account/DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Saber Stable Swap",
account_id: "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ",
solscan_url: "https://solscan.io/account/SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Saros AMM",
account_id: "SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr",
solscan_url: "https://solscan.io/account/SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Sanctum Multi-Validator SPL Stake Pool Program",
account_id: "SPMBzsVUuoHA4Jm6KunbsotaahvVikZs1JyTW6iJvbn",
solscan_url: "https://solscan.io/account/SPMBzsVUuoHA4Jm6KunbsotaahvVikZs1JyTW6iJvbn",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Sanctum Router Program",
account_id: "stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq",
solscan_url: "https://solscan.io/account/stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Sanctum: S Controller",
account_id: "5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kx",
solscan_url: "https://solscan.io/account/5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kx",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Sanctum Single Validator SPL Stake Pool Program",
account_id: "SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY",
solscan_url: "https://solscan.io/account/SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY",
idl_status: "solscan_account",
},
SolscanAccountSource {
label: "SharkyFi",
account_id: "SHARKobtfF1bHhxD2eqftjHBdVSCbKo9JtgK71FhELP",
solscan_url: "https://solscan.io/account/SHARKobtfF1bHhxD2eqftjHBdVSCbKo9JtgK71FhELP",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Solayer",
account_id: "sSo1iU21jBrU9VaJ8PJib1MtorefUV4fzC9GURa2KNn",
solscan_url: "https://solscan.io/account/sSo1iU21jBrU9VaJ8PJib1MtorefUV4fzC9GURa2KNn",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Solend Protocol",
account_id: "So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo",
solscan_url: "https://solscan.io/account/So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "SolFi",
account_id: "SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe",
solscan_url: "https://solscan.io/account/SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "SolFi V2",
account_id: "SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF",
solscan_url: "https://solscan.io/account/SV2EYYJyRz2YhfXwXnhNAevDEui5Q6yrfyo13WtupPF",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "stabble CLMM",
account_id: "6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6",
solscan_url: "https://solscan.io/account/6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "stabble Stable Swap",
account_id: "swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ",
solscan_url: "https://solscan.io/account/swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "stabble Weighted Swap",
account_id: "swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW",
solscan_url: "https://solscan.io/account/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Stake Pool",
account_id: "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy",
solscan_url: "https://solscan.io/account/SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Stake Program",
account_id: "Stake11111111111111111111111111111111111111",
solscan_url: "https://solscan.io/account/Stake11111111111111111111111111111111111111",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Step Finance Swap Program",
account_id: "SSwpMgqNDsyV7mAgN9ady4bDVu5ySjmmXejXvy2vLt1",
solscan_url: "https://solscan.io/account/SSwpMgqNDsyV7mAgN9ady4bDVu5ySjmmXejXvy2vLt1",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "StepN DOOAR Swap",
account_id: "Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j",
solscan_url: "https://solscan.io/account/Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Scorch",
account_id: "SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn",
solscan_url: "https://solscan.io/account/SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Streamflow",
account_id: "strmRqUCoQUgGUan5YhzUZa6KqdzwX5L6FpUxfmKg5m",
solscan_url: "https://solscan.io/account/strmRqUCoQUgGUan5YhzUZa6KqdzwX5L6FpUxfmKg5m#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Swap Program",
account_id: "SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8",
solscan_url: "https://solscan.io/account/SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Swig Program",
account_id: "swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB",
solscan_url: "https://solscan.io/account/swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "System Program",
account_id: "11111111111111111111111111111111",
solscan_url: "https://solscan.io/account/11111111111111111111111111111111",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Tessera V",
account_id: "TessVdML9pBGgG9yGks7o4HewRaXVAMuoVj4x83GLQH",
solscan_url: "https://solscan.io/account/TessVdML9pBGgG9yGks7o4HewRaXVAMuoVj4x83GLQH",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Titan Exchange Router",
account_id: "T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT",
solscan_url: "https://solscan.io/account/T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Token 2022 Program",
account_id: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
solscan_url: "https://solscan.io/account/TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Token Program",
account_id: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
solscan_url: "https://solscan.io/account/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Vertigo Program",
account_id: "vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ",
solscan_url: "https://solscan.io/account/vrTGoBuy5rYSxAfV3jaRJWHH6nN9WK4NRExGxsk1bCJ#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Virtuals",
account_id: "5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki",
solscan_url: "https://solscan.io/account/5U3EU2ubXtK84QcRjWVmYt9RaDyA8gKxdUrPFXmZyaki#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Woofi",
account_id: "WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb",
solscan_url: "https://solscan.io/account/WooFif76YGRNjk1pA8wCsN67aQsD9f9iLsz4NcJ1AVb#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Wormhole: Bridge",
account_id: "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb",
solscan_url: "https://solscan.io/account/wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "ZeroFi",
account_id: "ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY",
solscan_url: "https://solscan.io/account/ZERor4xhbUycZ6gb9ntrhqscUcZmAbQDjEAtCf4hbZY",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Zeta Matching Engine",
account_id: "zDEXqXEG7gAyxb1Kg9mK5fPnUdENCGKzWrM21RMdWRq",
solscan_url: "https://solscan.io/account/zDEXqXEG7gAyxb1Kg9mK5fPnUdENCGKzWrM21RMdWRq",
idl_status: "no_idl",
},
SolscanAccountSource {
label: "Zeta Program",
account_id: "ZETAxsqBRek56DhiGXrn75yj2NHU3aYUnxvHXpkf3aD",
solscan_url: "https://solscan.io/account/ZETAxsqBRek56DhiGXrn75yj2NHU3aYUnxvHXpkf3aD#programIdl",
idl_status: "solscan_program_idl",
},
SolscanAccountSource {
label: "Zora Program",
account_id: "zoRabwLGd5zXaV7Gxacppw8tcceXEiTrSKyNLSaSTUc",
solscan_url: "https://solscan.io/account/zoRabwLGd5zXaV7Gxacppw8tcceXEiTrSKyNLSaSTUc",
idl_status: "no_idl",
},
];

View File

@@ -78,6 +78,7 @@ pub use dtos::ProtocolCandidateDto;
pub use dtos::ProtocolCandidateSummaryDto;
pub use dtos::RewardEventDto;
pub use dtos::SwapDto;
pub use dtos::TokenAccountEventDto;
pub use dtos::TokenBurnEventDto;
pub use dtos::TokenDto;
pub use dtos::TokenMintEventDto;
@@ -124,6 +125,7 @@ pub use entities::ProtocolCandidateEntity;
pub use entities::ProtocolCandidateSummaryEntity;
pub use entities::RewardEventEntity;
pub use entities::SwapEntity;
pub use entities::TokenAccountEventEntity;
pub use entities::TokenBurnEventEntity;
pub use entities::TokenEntity;
pub use entities::TokenMintEventEntity;
@@ -155,6 +157,7 @@ pub use queries::query_dex_decode_replay_ledger_get_by_transaction;
pub use queries::query_dex_decode_replay_ledger_upsert;
pub use queries::query_dex_decoded_events_delete_by_key;
pub use queries::query_dex_decoded_events_delete_locally_covered_upstream_instruction_matches;
pub use queries::query_dex_decoded_events_delete_replaced_raydium_cpmm_instruction_audits;
pub use queries::query_dex_decoded_events_delete_meteora_dlmm_anchor_swap_instruction_audits;
pub use queries::query_dex_decoded_events_delete_related_instruction_audit;
pub use queries::query_dex_decoded_events_delete_replaced_raydium_clmm_instruction_audits;
@@ -264,6 +267,7 @@ pub use queries::query_reward_events_list_recent;
pub use queries::query_reward_events_upsert;
pub use queries::query_swaps_list_recent;
pub use queries::query_swaps_upsert;
pub use queries::query_token_account_events_upsert;
pub use queries::query_token_burn_events_list_recent;
pub use queries::query_token_burn_events_upsert;
pub use queries::query_token_mint_events_list_recent;

View File

@@ -42,6 +42,7 @@ mod protocol_candidate_summary;
mod reward_event;
mod swap;
mod token;
mod token_account_event;
mod token_burn_event;
mod token_mint_event;
mod trade_event;
@@ -136,6 +137,7 @@ pub use protocol_candidate_summary::ProtocolCandidateSummaryDto;
pub use reward_event::RewardEventDto;
pub use swap::SwapDto;
pub use token::TokenDto;
pub use token_account_event::TokenAccountEventDto;
pub use token_burn_event::TokenBurnEventDto;
pub use token_mint_event::TokenMintEventDto;
pub use trade_event::TradeEventDto;

View File

@@ -0,0 +1,140 @@
// file: kb_lib/src/db/dtos/token_account_event.rs
//! Token account event DTO.
/// Application-facing normalized token-account event DTO.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TokenAccountEventDto {
/// Optional numeric primary key.
pub id: std::option::Option<i64>,
/// Related transaction id.
pub transaction_id: std::option::Option<i64>,
/// Related decoded event id.
pub decoded_event_id: std::option::Option<i64>,
/// Related DEX id.
pub dex_id: std::option::Option<i64>,
/// Related pool id, when known.
pub pool_id: std::option::Option<i64>,
/// Related pair id, when known.
pub pair_id: std::option::Option<i64>,
/// Transaction signature.
pub signature: std::string::String,
/// Instruction index inside the transaction.
pub instruction_index: i64,
/// Optional slot number.
pub slot: std::option::Option<u64>,
/// Protocol name.
pub protocol_name: std::string::String,
/// Program id.
pub program_id: std::option::Option<std::string::String>,
/// Event kind.
pub event_kind: std::string::String,
/// Token account, when known.
pub token_account: std::option::Option<std::string::String>,
/// Token mint, when known.
pub token_mint: std::option::Option<std::string::String>,
/// Owner wallet, when known.
pub owner_wallet: std::option::Option<std::string::String>,
/// Token-account action.
pub account_action: std::option::Option<std::string::String>,
/// Raw decoded payload.
pub payload_json: std::option::Option<std::string::String>,
/// Execution timestamp.
pub executed_at: chrono::DateTime<chrono::Utc>,
}
impl TokenAccountEventDto {
/// Creates a new token-account event DTO.
#[allow(clippy::too_many_arguments)]
pub fn new(
transaction_id: std::option::Option<i64>,
decoded_event_id: std::option::Option<i64>,
dex_id: std::option::Option<i64>,
pool_id: std::option::Option<i64>,
pair_id: std::option::Option<i64>,
signature: std::string::String,
instruction_index: i64,
slot: std::option::Option<u64>,
protocol_name: std::string::String,
program_id: std::option::Option<std::string::String>,
event_kind: std::string::String,
token_account: std::option::Option<std::string::String>,
token_mint: std::option::Option<std::string::String>,
owner_wallet: std::option::Option<std::string::String>,
account_action: std::option::Option<std::string::String>,
payload_json: std::option::Option<std::string::String>,
) -> Self {
return Self {
id: None,
transaction_id,
decoded_event_id,
dex_id,
pool_id,
pair_id,
signature,
instruction_index,
slot,
protocol_name,
program_id,
event_kind,
token_account,
token_mint,
owner_wallet,
account_action,
payload_json,
executed_at: chrono::Utc::now(),
};
}
}
impl TryFrom<crate::TokenAccountEventEntity> for TokenAccountEventDto {
type Error = crate::Error;
fn try_from(entity: crate::TokenAccountEventEntity) -> Result<Self, Self::Error> {
let executed_at_result = chrono::DateTime::parse_from_rfc3339(&entity.executed_at);
let executed_at = match executed_at_result {
Ok(executed_at) => executed_at.with_timezone(&chrono::Utc),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot parse token account event executed_at '{}': {}",
entity.executed_at, error
)));
},
};
let slot = match entity.slot {
Some(slot) => {
let slot_result = u64::try_from(slot);
match slot_result {
Ok(slot) => Some(slot),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot convert token account event slot '{}' to u64: {}",
slot, error
)));
},
}
},
None => None,
};
return Ok(Self {
id: Some(entity.id),
transaction_id: entity.transaction_id,
decoded_event_id: entity.decoded_event_id,
dex_id: entity.dex_id,
pool_id: entity.pool_id,
pair_id: entity.pair_id,
signature: entity.signature,
instruction_index: entity.instruction_index,
slot,
protocol_name: entity.protocol_name,
program_id: entity.program_id,
event_kind: entity.event_kind,
token_account: entity.token_account,
token_mint: entity.token_mint,
owner_wallet: entity.owner_wallet,
account_action: entity.account_action,
payload_json: entity.payload_json,
executed_at,
});
}
}

View File

@@ -42,6 +42,7 @@ mod protocol_candidate_summary;
mod reward_event;
mod swap;
mod token;
mod token_account_event;
mod token_burn_event;
mod token_mint_event;
mod trade_event;
@@ -89,6 +90,7 @@ pub use protocol_candidate_summary::ProtocolCandidateSummaryEntity;
pub use reward_event::RewardEventEntity;
pub use swap::SwapEntity;
pub use token::TokenEntity;
pub use token_account_event::TokenAccountEventEntity;
pub use token_burn_event::TokenBurnEventEntity;
pub use token_mint_event::TokenMintEventEntity;
pub use trade_event::TradeEventEntity;

View File

@@ -0,0 +1,46 @@
// file: kb_lib/src/db/entities/token_account_event.rs
//! Token account event entity.
/// Persisted normalized token-account event row.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, sqlx::FromRow)]
pub struct TokenAccountEventEntity {
/// Numeric primary key.
pub id: i64,
/// Related transaction id.
pub transaction_id: std::option::Option<i64>,
/// Related decoded event id.
pub decoded_event_id: std::option::Option<i64>,
/// Related DEX id.
pub dex_id: std::option::Option<i64>,
/// Related pool id, when known.
pub pool_id: std::option::Option<i64>,
/// Related pair id, when known.
pub pair_id: std::option::Option<i64>,
/// Transaction signature.
pub signature: std::string::String,
/// Instruction index inside the transaction.
pub instruction_index: i64,
/// Optional slot number.
pub slot: std::option::Option<i64>,
/// Protocol name.
pub protocol_name: std::string::String,
/// Program id.
pub program_id: std::option::Option<std::string::String>,
/// Event kind.
pub event_kind: std::string::String,
/// Token account, when known.
pub token_account: std::option::Option<std::string::String>,
/// Token mint, when known.
pub token_mint: std::option::Option<std::string::String>,
/// Owner wallet, when known.
pub owner_wallet: std::option::Option<std::string::String>,
/// Token-account action.
pub account_action: std::option::Option<std::string::String>,
/// Raw decoded payload.
pub payload_json: std::option::Option<std::string::String>,
/// Execution timestamp encoded as RFC3339 UTC text.
pub executed_at: std::string::String,
/// Creation timestamp encoded as RFC3339 UTC text.
pub created_at: std::option::Option<std::string::String>,
}

View File

@@ -40,6 +40,7 @@ mod protocol_candidate;
mod reward_event;
mod swap;
mod token;
mod token_account_event;
mod token_burn_event;
mod token_mint_event;
mod trade_event;
@@ -77,6 +78,7 @@ pub use dex_decoded_event::query_dex_decoded_events_delete_locally_covered_upstr
pub use dex_decoded_event::query_dex_decoded_events_delete_meteora_dlmm_anchor_swap_instruction_audits;
pub use dex_decoded_event::query_dex_decoded_events_delete_related_instruction_audit;
pub use dex_decoded_event::query_dex_decoded_events_delete_replaced_raydium_clmm_instruction_audits;
pub use dex_decoded_event::query_dex_decoded_events_delete_replaced_raydium_cpmm_instruction_audits;
pub use dex_decoded_event::query_dex_decoded_events_get_by_key;
pub use dex_decoded_event::query_dex_decoded_events_get_latest_pump_fun_create_payload_by_mint;
pub use dex_decoded_event::query_dex_decoded_events_list_by_transaction_id;
@@ -185,6 +187,7 @@ pub use token::query_tokens_get_by_mint;
pub use token::query_tokens_list;
pub use token::query_tokens_list_missing_metadata;
pub use token::query_tokens_upsert;
pub use token_account_event::query_token_account_events_upsert;
pub use token_burn_event::query_token_burn_events_list_recent;
pub use token_burn_event::query_token_burn_events_upsert;
pub use token_mint_event::query_token_mint_events_list_recent;

View File

@@ -191,6 +191,136 @@ WHERE transaction_id = ?
}
}
/// Deletes Raydium CPMM instruction-audit rows for locally mapped CPMM instructions.
///
/// CPMM has one Anchor IDL-management instruction (`40f4bc78a7e9690a`) that is
/// decoded by the local Raydium audit-preservation pass rather than by the
/// CPMM instruction decoder itself because its payload is shorter than normal
/// CPMM instruction layouts. Once the named `raydium_cpmm.*` row exists, the
/// old `raydium_cpmm.instruction_audit` row is redundant and must be removed.
/// The allow-list also includes the regular CPMM instruction discriminators so
/// future replays do not leave duplicate audit rows for already covered entries.
pub async fn query_dex_decoded_events_delete_replaced_raydium_cpmm_instruction_audits(
database: &crate::Database,
transaction_id: std::option::Option<i64>,
) -> Result<u64, crate::Error> {
match database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let unlink_result = sqlx::query(
r#"
UPDATE k_sol_instruction_observations
SET decoded_event_id = NULL
WHERE decoded_event_id IN (
SELECT id
FROM k_sol_dex_decoded_events
WHERE protocol_name = 'raydium_cpmm'
AND event_kind = 'raydium_cpmm.instruction_audit'
AND (? IS NULL OR transaction_id = ?)
AND (
COALESCE(
json_extract(payload_json, '$.discriminatorHex'),
json_extract(payload_json, '$.discriminator_hex'),
json_extract(payload_json, '$.instructionDiscriminatorHex'),
json_extract(payload_json, '$.instruction_discriminator_hex')
) IN (
'40f4bc78a7e9690a',
'9c5420764587467b',
'1416567bc61cdb84',
'a78a4e95dfc2067e',
'8888fcddc2427e59',
'e445a52e51cb9a1d',
'8934edd4d7756c68',
'878802d889a9b5ca',
'f223c68952e1f2b6',
'afaf6d1f0d989bed',
'3f37fe4131b25979',
'8fbe5adac41e33de',
'37d96256a34ab4ad',
'313cae889a1c74c8',
'82576c062ee0757b',
'b712469c946da122'
)
OR instr(lower(COALESCE(payload_json, '')), '40f4bc78a7e9690a') > 0
OR EXISTS (
SELECT 1
FROM k_sol_dex_decoded_events named
WHERE named.transaction_id = k_sol_dex_decoded_events.transaction_id
AND named.protocol_name = 'raydium_cpmm'
AND named.event_kind = 'raydium_cpmm.anchor_idl_instruction'
)
)
)
"#,
)
.bind(transaction_id)
.bind(transaction_id)
.execute(pool)
.await;
if let Err(error) = unlink_result {
return Err(crate::Error::Db(format!(
"cannot unlink mapped Raydium CPMM instruction audit observations on sqlite: {}",
error
)));
}
let query_result = sqlx::query(
r#"
DELETE FROM k_sol_dex_decoded_events
WHERE protocol_name = 'raydium_cpmm'
AND event_kind = 'raydium_cpmm.instruction_audit'
AND (? IS NULL OR transaction_id = ?)
AND (
COALESCE(
json_extract(payload_json, '$.discriminatorHex'),
json_extract(payload_json, '$.discriminator_hex'),
json_extract(payload_json, '$.instructionDiscriminatorHex'),
json_extract(payload_json, '$.instruction_discriminator_hex')
) IN (
'40f4bc78a7e9690a',
'9c5420764587467b',
'1416567bc61cdb84',
'a78a4e95dfc2067e',
'8888fcddc2427e59',
'e445a52e51cb9a1d',
'8934edd4d7756c68',
'878802d889a9b5ca',
'f223c68952e1f2b6',
'afaf6d1f0d989bed',
'3f37fe4131b25979',
'8fbe5adac41e33de',
'37d96256a34ab4ad',
'313cae889a1c74c8',
'82576c062ee0757b',
'b712469c946da122'
)
OR instr(lower(COALESCE(payload_json, '')), '40f4bc78a7e9690a') > 0
OR EXISTS (
SELECT 1
FROM k_sol_dex_decoded_events named
WHERE named.transaction_id = k_sol_dex_decoded_events.transaction_id
AND named.protocol_name = 'raydium_cpmm'
AND named.event_kind = 'raydium_cpmm.anchor_idl_instruction'
)
)
"#,
)
.bind(transaction_id)
.bind(transaction_id)
.execute(pool)
.await;
match query_result {
Ok(result) => return Ok(result.rows_affected()),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot delete mapped Raydium CPMM instruction audit events on sqlite: {}",
error
)));
},
}
},
}
}
/// Deletes Raydium CLMM instruction-audit rows for locally mapped CLMM instructions.
///
/// The CLMM specialized decoder now emits named `raydium_clmm.*` rows for all

View File

@@ -323,7 +323,8 @@ SET
)
)
),
trade_count = (
trade_count = CASE
WHEN expected_db_target = 'k_sol_trade_events' THEN (
SELECT COUNT(te.id)
FROM k_sol_dex_decoded_events de
JOIN k_sol_trade_events te ON te.decoded_event_id = de.id
@@ -357,7 +358,10 @@ SET
)
)
)
),
)
ELSE 0
END,
materialized_count = CASE
WHEN expected_db_target = 'k_sol_trade_events' THEN (
SELECT COUNT(te.id)
@@ -604,6 +608,41 @@ SET
)
)
)
WHEN expected_db_target = 'k_sol_launch_events' THEN (
SELECT COUNT(le.id)
FROM k_sol_dex_decoded_events de
JOIN k_sol_launch_events le ON le.decoded_event_id = de.id
WHERE (
(k_sol_dex_event_coverage_entries.program_id IS NULL OR de.program_id = k_sol_dex_event_coverage_entries.program_id)
AND (
(
k_sol_dex_event_coverage_entries.local_event_kind IS NOT NULL
AND k_sol_dex_event_coverage_entries.local_event_kind <> ''
AND de.event_kind = k_sol_dex_event_coverage_entries.local_event_kind
)
OR (
k_sol_dex_event_coverage_entries.entry_name IS NOT NULL
AND (
json_extract(de.payload_json, '$.upstreamEntryName') = k_sol_dex_event_coverage_entries.entry_name
OR json_extract(de.payload_json, '$.upstreamInstructionName') = k_sol_dex_event_coverage_entries.entry_name
OR json_extract(de.payload_json, '$.upstreamEventName') = k_sol_dex_event_coverage_entries.entry_name
OR json_extract(de.payload_json, '$.entryName') = k_sol_dex_event_coverage_entries.entry_name
)
)
OR (
k_sol_dex_event_coverage_entries.discriminator_hex IS NOT NULL
AND k_sol_dex_event_coverage_entries.discriminator_hex <> ''
AND (
json_extract(de.payload_json, '$.upstreamDiscriminatorHex') = k_sol_dex_event_coverage_entries.discriminator_hex
OR json_extract(de.payload_json, '$.instructionDiscriminatorHex') = k_sol_dex_event_coverage_entries.discriminator_hex
OR json_extract(de.payload_json, '$.anchorEventDiscriminatorHex') = k_sol_dex_event_coverage_entries.discriminator_hex
OR json_extract(de.payload_json, '$.anchorEventDiscriminator') = k_sol_dex_event_coverage_entries.discriminator_hex
OR json_extract(de.payload_json, '$.discriminatorHex') = k_sol_dex_event_coverage_entries.discriminator_hex
)
)
)
)
)
ELSE materialized_count
END,
first_signature = (

View File

@@ -0,0 +1,176 @@
// file: kb_lib/src/db/queries/token_account_event.rs
//! Queries for `k_sol_token_account_events`.
/// Inserts or updates one normalized token-account event row.
pub async fn query_token_account_events_upsert(
database: &crate::Database,
dto: &crate::TokenAccountEventDto,
) -> Result<i64, crate::Error> {
let slot_i64 = match dto.slot {
Some(slot) => {
let slot_result = i64::try_from(slot);
match slot_result {
Ok(slot) => Some(slot),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot convert token account event slot '{}' to i64: {}",
slot, error
)));
},
}
},
None => None,
};
match database.connection() {
crate::DatabaseConnection::Sqlite(pool) => {
let existing_id = match dto.decoded_event_id {
Some(decoded_event_id) => {
let existing_result = sqlx::query_scalar::<sqlx::Sqlite, i64>(
r#"
SELECT id
FROM k_sol_token_account_events
WHERE decoded_event_id = ?
LIMIT 1
"#,
)
.bind(decoded_event_id)
.fetch_optional(pool)
.await;
match existing_result {
Ok(existing_id) => existing_id,
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot fetch k_sol_token_account_events id for decoded_event_id '{}' on sqlite: {}",
decoded_event_id, error
)));
},
}
},
None => None,
};
if let Some(id) = existing_id {
let update_result = sqlx::query(
r#"
UPDATE k_sol_token_account_events
SET
transaction_id = ?,
dex_id = ?,
pool_id = ?,
pair_id = ?,
signature = ?,
instruction_index = ?,
slot = ?,
protocol_name = ?,
program_id = ?,
event_kind = ?,
token_account = ?,
token_mint = ?,
owner_wallet = ?,
account_action = ?,
payload_json = ?,
executed_at = ?
WHERE id = ?
"#,
)
.bind(dto.transaction_id)
.bind(dto.dex_id)
.bind(dto.pool_id)
.bind(dto.pair_id)
.bind(dto.signature.clone())
.bind(dto.instruction_index)
.bind(slot_i64)
.bind(dto.protocol_name.clone())
.bind(dto.program_id.clone())
.bind(dto.event_kind.clone())
.bind(dto.token_account.clone())
.bind(dto.token_mint.clone())
.bind(dto.owner_wallet.clone())
.bind(dto.account_action.clone())
.bind(dto.payload_json.clone())
.bind(dto.executed_at.to_rfc3339())
.bind(id)
.execute(pool)
.await;
if let Err(error) = update_result {
return Err(crate::Error::Db(format!(
"cannot update k_sol_token_account_events id '{}' on sqlite: {}",
id, error
)));
}
return Ok(id);
}
let query_result = sqlx::query(
r#"
INSERT INTO k_sol_token_account_events (
transaction_id,
decoded_event_id,
dex_id,
pool_id,
pair_id,
signature,
instruction_index,
slot,
protocol_name,
program_id,
event_kind,
token_account,
token_mint,
owner_wallet,
account_action,
payload_json,
executed_at,
created_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"#,
)
.bind(dto.transaction_id)
.bind(dto.decoded_event_id)
.bind(dto.dex_id)
.bind(dto.pool_id)
.bind(dto.pair_id)
.bind(dto.signature.clone())
.bind(dto.instruction_index)
.bind(slot_i64)
.bind(dto.protocol_name.clone())
.bind(dto.program_id.clone())
.bind(dto.event_kind.clone())
.bind(dto.token_account.clone())
.bind(dto.token_mint.clone())
.bind(dto.owner_wallet.clone())
.bind(dto.account_action.clone())
.bind(dto.payload_json.clone())
.bind(dto.executed_at.to_rfc3339())
.bind(dto.executed_at.to_rfc3339())
.execute(pool)
.await;
if let Err(error) = query_result {
return Err(crate::Error::Db(format!(
"cannot insert k_sol_token_account_events on sqlite: {}",
error
)));
}
let id_result = sqlx::query_scalar::<sqlx::Sqlite, i64>(
r#"
SELECT id
FROM k_sol_token_account_events
WHERE decoded_event_id = ?
LIMIT 1
"#,
)
.bind(dto.decoded_event_id)
.fetch_one(pool)
.await;
match id_result {
Ok(id) => return Ok(id),
Err(error) => {
return Err(crate::Error::Db(format!(
"cannot fetch k_sol_token_account_events id for decoded_event_id '{:?}' on sqlite: {}",
dto.decoded_event_id, error
)));
},
}
},
}
}

View File

@@ -390,6 +390,42 @@ pub(crate) async fn ensure_schema(database: &crate::Database) -> Result<(), crat
if let Err(error) = result {
return Err(error);
}
let result = create_tbl_token_account_events(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_idx_token_account_events_transaction_id(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_idx_token_account_events_pool_id(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_uix_token_account_events_decoded_event_id(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_tbl_launch_events(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_idx_launch_events_transaction_id(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_idx_launch_events_pool_id(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_idx_launch_events_event_kind(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_uix_launch_events_decoded_event_id(pool).await;
if let Err(error) = result {
return Err(error);
}
let result = create_tbl_launch_surfaces(pool).await;
if let Err(error) = result {
return Err(error);
@@ -1490,7 +1526,7 @@ CREATE TABLE IF NOT EXISTS k_sol_instruction_observations (
updated_at TEXT NOT NULL,
FOREIGN KEY(transaction_id) REFERENCES k_sol_chain_transactions(id),
FOREIGN KEY(instruction_id) REFERENCES k_sol_chain_instructions(id),
FOREIGN KEY(decoded_event_id) REFERENCES k_sol_dex_decoded_events(id)
FOREIGN KEY(decoded_event_id) REFERENCES k_sol_dex_decoded_events(id) ON DELETE SET NULL
)
"#,
)
@@ -1786,6 +1822,94 @@ ON k_sol_dex_event_coverage_entries (event_family, expected_db_target)
.await;
}
async fn create_tbl_launch_events(pool: &sqlx::SqlitePool) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_tbl_launch_events",
r#"
CREATE TABLE IF NOT EXISTS k_sol_launch_events (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
transaction_id INTEGER NOT NULL,
decoded_event_id INTEGER NOT NULL UNIQUE,
dex_id INTEGER NULL,
pool_id INTEGER NULL,
pair_id INTEGER NULL,
signature TEXT NOT NULL,
slot INTEGER NULL,
protocol_name TEXT NOT NULL,
program_id TEXT NULL,
event_kind TEXT NOT NULL,
pool_account TEXT NULL,
actor_wallet TEXT NULL,
event_role TEXT NOT NULL,
related_account TEXT NULL,
related_mint TEXT NULL,
payload_json TEXT NOT NULL,
executed_at TEXT NOT NULL,
created_at TEXT NOT NULL,
FOREIGN KEY(transaction_id) REFERENCES k_sol_chain_transactions(id) ON DELETE CASCADE,
FOREIGN KEY(decoded_event_id) REFERENCES k_sol_dex_decoded_events(id) ON DELETE CASCADE,
FOREIGN KEY(dex_id) REFERENCES k_sol_dexes(id) ON DELETE SET NULL,
FOREIGN KEY(pool_id) REFERENCES k_sol_pools(id) ON DELETE SET NULL,
FOREIGN KEY(pair_id) REFERENCES k_sol_pairs(id) ON DELETE SET NULL
)
"#,
)
.await;
}
async fn create_idx_launch_events_transaction_id(
pool: &sqlx::SqlitePool,
) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_idx_launch_events_transaction_id",
r#"
CREATE INDEX IF NOT EXISTS idx_launch_events_transaction_id
ON k_sol_launch_events (transaction_id)
"#,
)
.await;
}
async fn create_idx_launch_events_pool_id(pool: &sqlx::SqlitePool) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_idx_launch_events_pool_id",
r#"
CREATE INDEX IF NOT EXISTS idx_launch_events_pool_id
ON k_sol_launch_events (pool_id)
"#,
)
.await;
}
async fn create_idx_launch_events_event_kind(pool: &sqlx::SqlitePool) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_idx_launch_events_event_kind",
r#"
CREATE INDEX IF NOT EXISTS idx_launch_events_event_kind
ON k_sol_launch_events (event_kind)
"#,
)
.await;
}
async fn create_uix_launch_events_decoded_event_id(
pool: &sqlx::SqlitePool,
) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_uix_launch_events_decoded_event_id",
r#"
CREATE UNIQUE INDEX IF NOT EXISTS uix_launch_events_decoded_event_id
ON k_sol_launch_events (decoded_event_id)
"#,
)
.await;
}
async fn create_tbl_launch_surfaces(pool: &sqlx::SqlitePool) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
@@ -2808,3 +2932,86 @@ WHERE decoded_event_id IS NOT NULL
)
.await;
}
/// Creates `k_sol_token_account_events`.
async fn create_tbl_token_account_events(pool: &sqlx::SqlitePool) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_tbl_token_account_events",
r#"
CREATE TABLE IF NOT EXISTS k_sol_token_account_events (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
transaction_id INTEGER NULL,
decoded_event_id INTEGER NULL,
dex_id INTEGER NULL,
pool_id INTEGER NULL,
pair_id INTEGER NULL,
signature TEXT NOT NULL,
instruction_index INTEGER NOT NULL,
slot INTEGER NULL,
protocol_name TEXT NOT NULL,
program_id TEXT NULL,
event_kind TEXT NOT NULL,
token_account TEXT NULL,
token_mint TEXT NULL,
owner_wallet TEXT NULL,
account_action TEXT NULL,
payload_json TEXT NULL,
executed_at TEXT NOT NULL,
created_at TEXT NULL,
FOREIGN KEY(transaction_id) REFERENCES k_sol_chain_transactions(id),
FOREIGN KEY(decoded_event_id) REFERENCES k_sol_dex_decoded_events(id),
FOREIGN KEY(dex_id) REFERENCES k_sol_dexes(id),
FOREIGN KEY(pool_id) REFERENCES k_sol_pools(id),
FOREIGN KEY(pair_id) REFERENCES k_sol_pairs(id)
)
"#,
)
.await;
}
/// Creates index on `k_sol_token_account_events(transaction_id)`.
async fn create_idx_token_account_events_transaction_id(
pool: &sqlx::SqlitePool,
) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_idx_token_account_events_transaction_id",
r#"
CREATE INDEX IF NOT EXISTS idx_token_account_events_transaction_id
ON k_sol_token_account_events (transaction_id)
"#,
)
.await;
}
/// Creates index on `k_sol_token_account_events(pool_id)`.
async fn create_idx_token_account_events_pool_id(
pool: &sqlx::SqlitePool,
) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_idx_token_account_events_pool_id",
r#"
CREATE INDEX IF NOT EXISTS idx_token_account_events_pool_id
ON k_sol_token_account_events (pool_id)
"#,
)
.await;
}
/// Creates unique index on `k_sol_token_account_events(decoded_event_id)`.
async fn create_uix_token_account_events_decoded_event_id(
pool: &sqlx::SqlitePool,
) -> Result<(), crate::Error> {
return execute_sqlite_schema_statement(
pool,
"create_uix_token_account_events_decoded_event_id",
r#"
CREATE UNIQUE INDEX IF NOT EXISTS uix_token_account_events_decoded_event_id
ON k_sol_token_account_events (decoded_event_id)
WHERE decoded_event_id IS NOT NULL
"#,
)
.await;
}

View File

@@ -16,6 +16,7 @@ mod pump_swap;
mod raydium_amm_v4;
mod raydium_clmm;
mod raydium_cpmm;
pub(crate) mod raydium_launchpad;
pub use dexlab::DexlabCreatePoolDecoded;
pub use dexlab::DexlabDecodedEvent;
@@ -74,8 +75,8 @@ pub use raydium_clmm::RaydiumClmmCollectProtocolFeeDecoded;
pub use raydium_clmm::RaydiumClmmCreatePoolDecoded;
pub use raydium_clmm::RaydiumClmmDecodedEvent;
pub use raydium_clmm::RaydiumClmmDecodedInstructionEvent;
pub use raydium_clmm::RaydiumClmmProgramDataEventDecoded;
pub use raydium_clmm::RaydiumClmmDecoder;
pub use raydium_clmm::RaydiumClmmProgramDataEventDecoded;
pub use raydium_clmm::RaydiumClmmSwapLegacyDecoded;
pub use raydium_clmm::RaydiumClmmSwapV2Decoded;
pub use raydium_clmm::decode_raydium_clmm_instruction;

View File

@@ -56,6 +56,10 @@ const RAYDIUM_CPMM_UPDATE_POOL_STATUS_DISCRIMINATOR: [u8; 8] = [130, 87, 108, 6,
/// Anchor self-CPI log selector used by Raydium CPMM events.
const RAYDIUM_CPMM_ANCHOR_SELF_CPI_LOG_SELECTOR: [u8; 8] = [228, 69, 165, 46, 81, 203, 154, 29];
/// Anchor IDL management discriminator observed on Raydium CPMM (`IdlCreateAccount` / `IdlCloseAccount`).
const RAYDIUM_CPMM_ANCHOR_IDL_INSTRUCTION_DISCRIMINATOR: [u8; 8] =
[64, 244, 188, 120, 167, 233, 105, 10];
/// Raydium CPMM `LpChangeEvent` Anchor event discriminator.
const RAYDIUM_CPMM_LP_CHANGE_EVENT_DISCRIMINATOR: [u8; 8] = [121, 163, 205, 201, 57, 218, 117, 60];
@@ -766,6 +770,9 @@ pub fn classify_raydium_cpmm_instruction_data(
if discriminator == RAYDIUM_CPMM_UPDATE_POOL_STATUS_DISCRIMINATOR {
return Some("update_pool_status");
}
if discriminator == RAYDIUM_CPMM_ANCHOR_IDL_INSTRUCTION_DISCRIMINATOR {
return Some("anchor_idl_instruction");
}
return None;
}
@@ -1172,7 +1179,6 @@ fn build_raydium_cpmm_swap(
});
}
fn normalize_raydium_cpmm_mints(
mint_a: &str,
mint_b: &str,

View File

@@ -0,0 +1,316 @@
// file: kb_lib/src/dex/raydium_launchpad.rs
//! Raydium Launchpad instruction and event helper metadata.
//!
//! The specialized `0.7.50` implementation still decodes Launchpad through
//! the shared persistence-oriented decoder. This module centralizes the stable
//! Launchpad account-layout hints so they do not remain hidden inside the
//! generic Raydium audit fallback.
/// Static account layout for a locally mapped Raydium Launchpad instruction.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct RaydiumLaunchpadAccountLayout {
/// IDL instruction name.
pub(crate) instruction_name: &'static str,
/// Local decoded event kind.
pub(crate) event_kind: &'static str,
/// Minimum projected account count required before applying account hints.
pub(crate) minimum_account_count: usize,
/// Candidate pool-state account index in the projected instruction account list.
pub(crate) pool_account_index: std::option::Option<usize>,
/// Candidate base mint account index in the projected instruction account list.
pub(crate) base_mint_index: std::option::Option<usize>,
/// Candidate quote mint account index in the projected instruction account list.
pub(crate) quote_mint_index: std::option::Option<usize>,
/// Whether this instruction creates a Launchpad pool/bonding curve.
pub(crate) creates_pool: bool,
}
/// Returns local account-layout hints for one Raydium Launchpad instruction discriminator.
pub(crate) fn account_layout(
discriminator_hex: &str,
account_count: usize,
) -> std::option::Option<RaydiumLaunchpadAccountLayout> {
let layout = match discriminator_hex {
"faea0d7bd59c13ec" => RaydiumLaunchpadAccountLayout {
instruction_name: "buy_exact_in",
event_kind: "raydium_launchpad.buy_exact_in",
minimum_account_count: 11,
pool_account_index: Some(4),
base_mint_index: Some(9),
quote_mint_index: Some(10),
creates_pool: false,
},
"18d3742869039938" => RaydiumLaunchpadAccountLayout {
instruction_name: "buy_exact_out",
event_kind: "raydium_launchpad.buy_exact_out",
minimum_account_count: 11,
pool_account_index: Some(4),
base_mint_index: Some(9),
quote_mint_index: Some(10),
creates_pool: false,
},
"7bb4b8816fb9bb3b" => RaydiumLaunchpadAccountLayout {
instruction_name: "close_platform_global_access",
event_kind: "raydium_launchpad.close_platform_global_access",
minimum_account_count: 4,
pool_account_index: None,
base_mint_index: None,
quote_mint_index: None,
creates_pool: false,
},
"a25b92c75d85eaed" => RaydiumLaunchpadAccountLayout {
instruction_name: "create_platform_global_access",
event_kind: "raydium_launchpad.create_platform_global_access",
minimum_account_count: 5,
pool_account_index: None,
base_mint_index: None,
quote_mint_index: None,
creates_pool: false,
},
"9247ad4562130f6a" => RaydiumLaunchpadAccountLayout {
instruction_name: "create_platform_vesting_account",
event_kind: "raydium_launchpad.create_platform_vesting_account",
minimum_account_count: 6,
pool_account_index: Some(3),
base_mint_index: None,
quote_mint_index: None,
creates_pool: false,
},
"e445a52e51cb9a1d" => no_account_layout("cpi_event", "raydium_launchpad.cpi_event"),
"1a618acb84ab8dfc" => {
no_account_layout("claim_creator_fee", "raydium_launchpad.claim_creator_fee")
},
"9c27d0874ced3d48" => RaydiumLaunchpadAccountLayout {
instruction_name: "claim_platform_fee",
event_kind: "raydium_launchpad.claim_platform_fee",
minimum_account_count: 7,
pool_account_index: Some(2),
base_mint_index: None,
quote_mint_index: Some(6),
creates_pool: false,
},
"75f1c6a8f8da501d" => no_account_layout(
"claim_platform_fee_from_vault",
"raydium_launchpad.claim_platform_fee_from_vault",
),
"3121681ebd9d4f23" => RaydiumLaunchpadAccountLayout {
instruction_name: "claim_vested_token",
event_kind: "raydium_launchpad.claim_vested_token",
minimum_account_count: 7,
pool_account_index: Some(2),
base_mint_index: Some(6),
quote_mint_index: None,
creates_pool: false,
},
"3cadf767045d8230" => RaydiumLaunchpadAccountLayout {
instruction_name: "collect_fee",
event_kind: "raydium_launchpad.collect_fee",
minimum_account_count: 6,
pool_account_index: Some(2),
base_mint_index: None,
quote_mint_index: Some(5),
creates_pool: false,
},
"ffba96dfeb76c9ba" => RaydiumLaunchpadAccountLayout {
instruction_name: "collect_migrate_fee",
event_kind: "raydium_launchpad.collect_migrate_fee",
minimum_account_count: 6,
pool_account_index: Some(2),
base_mint_index: None,
quote_mint_index: Some(5),
creates_pool: false,
},
"c9cff3724b6f2fbd" => no_account_layout("create_config", "raydium_launchpad.create_config"),
"b05ac4affd71dc14" => {
no_account_layout("create_platform_config", "raydium_launchpad.create_platform_config")
},
"81b2020dd9ace6da" => RaydiumLaunchpadAccountLayout {
instruction_name: "create_vesting_account",
event_kind: "raydium_launchpad.create_vesting_account",
minimum_account_count: 5,
pool_account_index: Some(2),
base_mint_index: None,
quote_mint_index: None,
creates_pool: false,
},
"afaf6d1f0d989bed" => initialize_layout("initialize", "raydium_launchpad.initialize"),
"4399af27da102620" => initialize_layout("initialize_v2", "raydium_launchpad.initialize_v2"),
"25be7ede2c9aab11" => initialize_layout(
"initialize_with_token_2022",
"raydium_launchpad.initialize_with_token_2022",
),
"cf52c091fecf91df" => RaydiumLaunchpadAccountLayout {
instruction_name: "migrate_to_amm",
event_kind: "raydium_launchpad.migrate_to_amm",
minimum_account_count: 28,
pool_account_index: Some(23),
base_mint_index: Some(1),
quote_mint_index: Some(2),
creates_pool: false,
},
"885cc8671cda908c" => RaydiumLaunchpadAccountLayout {
instruction_name: "migrate_to_cpswap",
event_kind: "raydium_launchpad.migrate_to_cpswap",
minimum_account_count: 22,
pool_account_index: Some(17),
base_mint_index: Some(1),
quote_mint_index: Some(2),
creates_pool: false,
},
"1b1e3ea95de01891" => no_account_layout(
"remove_platform_curve_param",
"raydium_launchpad.remove_platform_curve_param",
),
"9527de9bd37c981a" => RaydiumLaunchpadAccountLayout {
instruction_name: "sell_exact_in",
event_kind: "raydium_launchpad.sell_exact_in",
minimum_account_count: 11,
pool_account_index: Some(4),
base_mint_index: Some(9),
quote_mint_index: Some(10),
creates_pool: false,
},
"5fc8472208090ba6" => RaydiumLaunchpadAccountLayout {
instruction_name: "sell_exact_out",
event_kind: "raydium_launchpad.sell_exact_out",
minimum_account_count: 11,
pool_account_index: Some(4),
base_mint_index: Some(9),
quote_mint_index: Some(10),
creates_pool: false,
},
"1d9efcbf0a53db63" => no_account_layout("update_config", "raydium_launchpad.update_config"),
"c33c4c81922d438f" => {
no_account_layout("update_platform_config", "raydium_launchpad.update_platform_config")
},
"8a908afadc800439" => no_account_layout(
"update_platform_curve_param",
"raydium_launchpad.update_platform_curve_param",
),
_ => return None,
};
return Some(sanitize_account_layout(layout, account_count));
}
fn sanitize_account_layout(
layout: RaydiumLaunchpadAccountLayout,
account_count: usize,
) -> RaydiumLaunchpadAccountLayout {
let pool_account_index = retain_existing_index(layout.pool_account_index, account_count);
let base_mint_index = retain_existing_index(layout.base_mint_index, account_count);
let quote_mint_index = retain_existing_index(layout.quote_mint_index, account_count);
return RaydiumLaunchpadAccountLayout {
instruction_name: layout.instruction_name,
event_kind: layout.event_kind,
minimum_account_count: layout.minimum_account_count,
pool_account_index,
base_mint_index,
quote_mint_index,
creates_pool: layout.creates_pool
&& pool_account_index.is_some()
&& base_mint_index.is_some()
&& quote_mint_index.is_some(),
};
}
fn retain_existing_index(
index: std::option::Option<usize>,
account_count: usize,
) -> std::option::Option<usize> {
let index = match index {
Some(index) => index,
None => return None,
};
if index < account_count {
return Some(index);
}
return None;
}
fn no_account_layout(
instruction_name: &'static str,
event_kind: &'static str,
) -> RaydiumLaunchpadAccountLayout {
return RaydiumLaunchpadAccountLayout {
instruction_name,
event_kind,
minimum_account_count: 1,
pool_account_index: None,
base_mint_index: None,
quote_mint_index: None,
creates_pool: false,
};
}
fn initialize_layout(
instruction_name: &'static str,
event_kind: &'static str,
) -> RaydiumLaunchpadAccountLayout {
return RaydiumLaunchpadAccountLayout {
instruction_name,
event_kind,
minimum_account_count: 18,
pool_account_index: Some(5),
base_mint_index: Some(6),
quote_mint_index: Some(7),
creates_pool: true,
};
}
#[cfg(test)]
mod tests {
#[test]
fn initialize_layout_exposes_carbon_account_order() {
let layout = super::account_layout("afaf6d1f0d989bed", 18);
let layout = match layout {
Some(layout) => layout,
None => panic!("initialize layout must resolve"),
};
assert_eq!(layout.instruction_name, "initialize");
assert_eq!(layout.pool_account_index, Some(5));
assert_eq!(layout.base_mint_index, Some(6));
assert_eq!(layout.quote_mint_index, Some(7));
assert!(layout.creates_pool);
}
#[test]
fn platform_vesting_layout_exposes_pool_state() {
let layout = super::account_layout("9247ad4562130f6a", 6);
let layout = match layout {
Some(layout) => layout,
None => panic!("create_platform_vesting_account layout must resolve"),
};
assert_eq!(layout.instruction_name, "create_platform_vesting_account");
assert_eq!(layout.pool_account_index, Some(3));
}
#[test]
fn buy_layout_keeps_audit_only_pool_hints() {
let layout = super::account_layout("faea0d7bd59c13ec", 11);
let layout = match layout {
Some(layout) => layout,
None => panic!("buy layout must resolve"),
};
assert_eq!(layout.event_kind, "raydium_launchpad.buy_exact_in");
assert_eq!(layout.pool_account_index, Some(4));
assert_eq!(layout.base_mint_index, Some(9));
assert_eq!(layout.quote_mint_index, Some(10));
assert!(!layout.creates_pool);
}
#[test]
fn known_discriminator_still_maps_when_account_list_is_truncated() {
let layout = super::account_layout("cf52c091fecf91df", 1);
let layout = match layout {
Some(layout) => layout,
None => panic!("migrate_to_amm layout must resolve"),
};
assert_eq!(layout.instruction_name, "migrate_to_amm");
assert_eq!(layout.event_kind, "raydium_launchpad.migrate_to_amm");
assert_eq!(layout.pool_account_index, None);
assert_eq!(layout.base_mint_index, None);
assert_eq!(layout.quote_mint_index, None);
assert!(!layout.creates_pool);
}
}

View File

@@ -123,7 +123,7 @@ mod tests {
#[test]
fn planned_launch_surfaces_are_present_but_disabled() {
let codes = [
"raydium_launchlab",
"raydium_launchpad",
"letsbonk",
"boop_fun",
"moonshot",

File diff suppressed because it is too large Load Diff

View File

@@ -111,6 +111,9 @@ impl DexDetectService {
crate::dex_detection_route::DexDetectionRoute::RaydiumClmmTrade => {
self.detect_raydium_clmm_trade(&transaction, decoded_event).await
},
crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool => {
self.detect_raydium_launchpad_pool(&transaction, decoded_event).await
},
crate::dex_detection_route::DexDetectionRoute::PumpFunCreateV2Token => {
self.detect_pump_fun_create_v2_token(&transaction, decoded_event).await
},
@@ -647,6 +650,24 @@ impl DexDetectService {
return Ok(detection_result);
}
async fn detect_raydium_launchpad_pool(
&self,
transaction: &crate::ChainTransactionDto,
decoded_event: &crate::DexDecodedEventDto,
) -> Result<crate::DexPoolDetectionResult, crate::Error> {
return self
.detect_materialized_pool_from_decoded_event(
transaction,
decoded_event,
"raydium_launchpad",
crate::PoolKind::BondingCurve,
crate::PoolStatus::Pending,
"signal.dex.raydium_launchpad",
)
.await;
}
async fn detect_raydium_cpmm_trade(
&self,
transaction: &crate::ChainTransactionDto,

View File

@@ -13,6 +13,8 @@ pub(crate) enum DexDetectionRoute {
RaydiumCpmmTrade,
/// Raydium CLMM trade route.
RaydiumClmmTrade,
/// Raydium Launchpad pool or bonding-curve creation route.
RaydiumLaunchpadPool,
/// Pump.fun create token route.
PumpFunCreateV2Token,
/// Pump.fun trade route.
@@ -62,6 +64,27 @@ pub(crate) fn dex_detection_route(
("raydium_clmm", "raydium_clmm.swap_v2") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumClmmTrade);
},
("raydium_launchpad", "raydium_launchpad.initialize") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("raydium_launchpad", "raydium_launchpad.initialize_v2") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("raydium_launchpad", "raydium_launchpad.initialize_with_token_2022") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("raydium_launchpad", "raydium_launchpad.buy_exact_in") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("raydium_launchpad", "raydium_launchpad.buy_exact_out") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("raydium_launchpad", "raydium_launchpad.sell_exact_in") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("raydium_launchpad", "raydium_launchpad.sell_exact_out") => {
return Some(crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
},
("pump_fun", "pump_fun.create_v2_token") => {
return Some(crate::dex_detection_route::DexDetectionRoute::PumpFunCreateV2Token);
},
@@ -233,6 +256,26 @@ mod tests {
assert!(!crate::dex_detection_route::decoded_event_has_full_pool_context(&event));
}
#[test]
fn raydium_launchpad_initialize_route_requires_full_pool_context() {
let event = make_decoded_event(
"raydium_launchpad",
"raydium_launchpad.initialize",
Some("Pool111"),
Some("TokenA111"),
Some("TokenB111"),
);
let route_option = crate::dex_detection_route::dex_detection_route(&event);
let route = match route_option {
Some(route) => route,
None => panic!("route must be selected"),
};
assert_eq!(route, crate::dex_detection_route::DexDetectionRoute::RaydiumLaunchpadPool);
assert!(crate::dex_detection_route::dex_detection_route_requires_full_pool_context(
route
));
}
#[test]
fn pump_fun_create_token_route_does_not_require_full_pool_context() {
let event = make_decoded_event(

View File

@@ -23,6 +23,8 @@ pub enum DexEventCategory {
PoolLifecycle,
/// Protocol administration, configuration or permission update event.
Admin,
/// Token-account creation, close, wrap or unwrap event.
TokenAccount,
/// Informational or audit-only decoded event retained for corpus analysis.
Informational,
/// Event kind that is not classified yet.
@@ -39,6 +41,7 @@ impl DexEventCategory {
Self::Reward => return "reward",
Self::PoolLifecycle => return "pool_lifecycle",
Self::Admin => return "admin",
Self::TokenAccount => return "token_account",
Self::Informational => return "informational",
Self::Unknown => return "unknown",
}
@@ -76,6 +79,10 @@ pub enum DexEventLifecycleKind {
Reward,
/// Administration, configuration or permission update event.
AdminConfig,
/// Token-account creation event.
TokenAccountCreate,
/// Token-account close event.
TokenAccountClose,
/// Instruction-level audit event retained for corpus analysis.
InstructionAudit,
/// Event kind that is not classified yet.
@@ -100,6 +107,8 @@ impl DexEventLifecycleKind {
Self::FeeCollection => return "fee_collection",
Self::Reward => return "reward",
Self::AdminConfig => return "admin_config",
Self::TokenAccountCreate => return "token_account_create",
Self::TokenAccountClose => return "token_account_close",
Self::InstructionAudit => return "instruction_audit",
Self::Unknown => return "unknown",
}
@@ -157,6 +166,9 @@ pub fn classify_dex_event_category(event_kind: &str) -> DexEventCategory {
if is_dex_admin_event_kind(event_kind) {
return DexEventCategory::Admin;
}
if is_dex_token_account_event_kind(event_kind) {
return DexEventCategory::TokenAccount;
}
if is_dex_trade_event_kind(event_kind) {
return DexEventCategory::Trade;
}
@@ -215,6 +227,12 @@ pub fn classify_dex_event_lifecycle_kind(event_kind: &str) -> DexEventLifecycleK
if is_dex_admin_event_kind(event_kind) {
return DexEventLifecycleKind::AdminConfig;
}
if is_dex_token_account_close_event_kind(event_kind) {
return DexEventLifecycleKind::TokenAccountClose;
}
if is_dex_token_account_create_event_kind(event_kind) {
return DexEventLifecycleKind::TokenAccountCreate;
}
if is_dex_trade_event_kind(event_kind) {
return DexEventLifecycleKind::TradeSwap;
}
@@ -254,6 +272,7 @@ pub fn classify_dex_event_actionability(
DexEventCategory::Reward => return DexEventActionability::NonTradeUseful,
DexEventCategory::PoolLifecycle => return DexEventActionability::NonTradeUseful,
DexEventCategory::Admin => return DexEventActionability::NonTradeUseful,
DexEventCategory::TokenAccount => return DexEventActionability::NonTradeUseful,
DexEventCategory::Informational => return DexEventActionability::Informational,
DexEventCategory::Trade => return DexEventActionability::NonActionableTrade,
DexEventCategory::Unknown => return DexEventActionability::Unknown,
@@ -278,6 +297,18 @@ pub fn is_dex_informational_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".instruction_audit") {
return true;
}
if event_kind.ends_with(".cpi_event") {
return true;
}
if event_kind.ends_with(".anchor_idl_instruction") {
return true;
}
if event_kind.contains(".idl_") {
return true;
}
if event_kind.contains(".liquidity_calculate_event") {
return true;
}
if event_kind.ends_with("_audit") {
return true;
}
@@ -289,6 +320,9 @@ pub fn is_dex_informational_event_kind(event_kind: &str) -> bool {
/// Returns true when the event kind represents a swap-like event.
pub fn is_dex_trade_event_kind(event_kind: &str) -> bool {
if event_kind == "raydium_launchpad.trade_event" {
return true;
}
if event_kind.ends_with(".buy") {
return true;
}
@@ -332,9 +366,6 @@ pub fn is_dex_liquidity_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".liquidity_change_event") {
return true;
}
if event_kind.contains(".liquidity_calculate_event") {
return true;
}
if event_kind.contains(".withdraw") {
return true;
}
@@ -362,6 +393,9 @@ pub fn is_dex_liquidity_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".close_position") {
return true;
}
if event_kind.contains(".close_protocol_position") {
return true;
}
if event_kind.contains(".position_close") {
return true;
}
@@ -404,6 +438,9 @@ pub fn is_dex_position_open_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".open_position") {
return true;
}
if event_kind.contains(".create_personal_position_event") {
return true;
}
if event_kind.contains(".position_create") {
return true;
}
@@ -415,11 +452,23 @@ pub fn is_dex_position_close_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".close_position") {
return true;
}
if event_kind.contains(".close_protocol_position") {
return true;
}
return false;
}
/// Returns true for fee collection events.
pub fn is_dex_fee_event_kind(event_kind: &str) -> bool {
if event_kind.contains("claim_creator_fee") {
return true;
}
if event_kind.contains("claim_platform_fee") {
return true;
}
if event_kind.contains("collect_migrate_fee") {
return true;
}
if event_kind.contains("collect_creator_fee") {
return true;
}
@@ -518,6 +567,21 @@ pub fn is_dex_pool_lifecycle_event_kind(event_kind: &str) -> bool {
/// Returns true for launch or bonding-curve creation events.
pub fn is_dex_launch_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".claim_vested_event") {
return true;
}
if event_kind.contains(".claim_vested_token") {
return true;
}
if event_kind.contains(".create_platform_vesting_account") {
return true;
}
if event_kind.contains(".create_vesting_account") {
return true;
}
if event_kind.contains(".create_vesting_event") {
return true;
}
if event_kind.contains("pump_fun.create") {
return true;
}
@@ -586,9 +650,15 @@ pub fn is_dex_pool_creation_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".create_pool") {
return true;
}
if event_kind.contains(".create_customizable_pool") {
return true;
}
if event_kind.contains(".pool_created_event") {
return true;
}
if event_kind.contains(".pool_create_event") {
return true;
}
if event_kind.contains(".create_amm") {
return true;
}
@@ -606,8 +676,53 @@ pub fn is_dex_pair_creation_event_kind(event_kind: &str) -> bool {
return false;
}
/// Returns true for token-account lifecycle events detected by DEX decoders.
pub fn is_dex_token_account_event_kind(event_kind: &str) -> bool {
if is_dex_token_account_create_event_kind(event_kind) {
return true;
}
if is_dex_token_account_close_event_kind(event_kind) {
return true;
}
return false;
}
/// Returns true for token-account creation events detected by DEX decoders.
pub fn is_dex_token_account_create_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".create_support_mint_associated") {
return true;
}
if event_kind.contains(".create_ata") {
return true;
}
if event_kind.contains(".init_account") {
return true;
}
return false;
}
/// Returns true for token-account close events detected by DEX decoders.
pub fn is_dex_token_account_close_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".close_account") {
return true;
}
return false;
}
/// Returns true for admin, configuration or permission changes.
pub fn is_dex_admin_event_kind(event_kind: &str) -> bool {
if event_kind.contains(".close_platform_global_access") {
return true;
}
if event_kind.contains(".create_platform_global_access") {
return true;
}
if event_kind.contains(".create_operation_account") {
return true;
}
if event_kind.contains("platform_curve_param") {
return true;
}
if event_kind.contains(".initialize_with_permission") {
return false;
}

View File

@@ -183,7 +183,11 @@ impl DexEventCoverageService {
fn build_coverage_entry_from_upstream(
entry: &crate::UpstreamRegistryEntryDto,
) -> crate::DexEventCoverageEntryDto {
let event_family = infer_event_family(entry.entry_name.as_str(), entry.entry_kind.as_str());
let event_family = infer_event_family_for_entry(
entry.decoder_code.as_str(),
entry.entry_name.as_str(),
entry.entry_kind.as_str(),
);
let expected_db_target = infer_expected_db_target_for_entry(
entry.decoder_code.as_str(),
entry.entry_name.as_str(),
@@ -211,11 +215,79 @@ fn infer_expected_db_target_for_entry(
event_family: std::option::Option<&str>,
entry_kind: &str,
) -> std::option::Option<std::string::String> {
if decoder_code == "raydium_cpmm" && entry_name == "swap_event" {
if decoder_code == "raydium_cpmm"
&& (entry_name == "swap_event" || entry_name == "anchor_idl_instruction")
{
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string());
}
if decoder_code == "raydium_clmm" && entry_name == "initialize_reward" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_REWARD_EVENTS.to_string());
if decoder_code == "raydium_clmm" {
if entry_name == "initialize_reward" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_REWARD_EVENTS.to_string());
}
if entry_name == "swap_event" || entry_name == "swap_router_base_in" {
return Some(
crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string(),
);
}
if entry_name == "open_position"
|| entry_name == "close_position"
|| entry_name == "close_protocol_position"
{
return Some(
crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string(),
);
}
}
if decoder_code == "raydium_launchpad" {
if entry_name == "trade_event" {
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_TRADE_EVENTS.to_string());
}
if entry_name == "buy_exact_in"
|| entry_name == "buy_exact_out"
|| entry_name == "sell_exact_in"
|| entry_name == "sell_exact_out"
{
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_LAUNCH_EVENTS.to_string());
}
if entry_name == "initialize"
|| entry_name == "initialize_v2"
|| entry_name == "initialize_with_token_2022"
|| entry_name == "pool_create_event"
{
return Some(
crate::DexEventCoverageEntryDto::DB_TARGET_POOL_LIFECYCLE_EVENTS.to_string(),
);
}
if entry_name == "claim_creator_fee"
|| entry_name == "claim_platform_fee"
|| entry_name == "claim_platform_fee_from_vault"
|| entry_name == "collect_fee"
|| entry_name == "collect_migrate_fee"
{
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_FEE_EVENTS.to_string());
}
if entry_name == "close_platform_global_access"
|| entry_name == "create_config"
|| entry_name == "create_platform_config"
|| entry_name == "create_platform_global_access"
|| entry_name == "remove_platform_curve_param"
|| entry_name == "update_config"
|| entry_name == "update_platform_config"
|| entry_name == "update_platform_curve_param"
{
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_POOL_ADMIN_EVENTS.to_string());
}
if entry_name == "claim_vested_event"
|| entry_name == "claim_vested_token"
|| entry_name == "create_platform_vesting_account"
|| entry_name == "create_vesting_account"
|| entry_name == "create_vesting_event"
|| entry_name == "migrate_to_amm"
|| entry_name == "migrate_to_cpswap"
{
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_LAUNCH_EVENTS.to_string());
}
return Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string());
}
return infer_expected_db_target(event_family, entry_kind);
}
@@ -241,6 +313,7 @@ fn infer_expected_db_target(
"liquidity" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS,
"liquidity_add" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS,
"liquidity_remove" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS,
"liquidity_change" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS,
"position_open" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS,
"position_close" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS,
"fee" => crate::DexEventCoverageEntryDto::DB_TARGET_FEE_EVENTS,
@@ -264,6 +337,10 @@ fn infer_expected_db_target(
"unlock" => crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_LOCK_EVENTS,
"launch" => crate::DexEventCoverageEntryDto::DB_TARGET_LAUNCH_EVENTS,
"migration" => crate::DexEventCoverageEntryDto::DB_TARGET_LAUNCH_EVENTS,
"vesting" => crate::DexEventCoverageEntryDto::DB_TARGET_LAUNCH_EVENTS,
"liquidity_calculation" => crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY,
"cpi_transport" => crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY,
"idl_management" => crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY,
"stake" => crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY,
"unstake" => crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY,
_ => crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY,
@@ -271,6 +348,99 @@ fn infer_expected_db_target(
return Some(target.to_string());
}
fn infer_event_family_for_entry(
decoder_code: &str,
entry_name: &str,
entry_kind: &str,
) -> std::option::Option<std::string::String> {
if decoder_code == "raydium_launchpad" {
return infer_raydium_launchpad_event_family(entry_name, entry_kind);
}
if decoder_code == "raydium_clmm" {
return infer_raydium_clmm_event_family(entry_name, entry_kind);
}
if decoder_code == "raydium_cpmm" {
return infer_raydium_cpmm_event_family(entry_name, entry_kind);
}
return infer_event_family(entry_name, entry_kind);
}
fn infer_raydium_cpmm_event_family(
entry_name: &str,
entry_kind: &str,
) -> std::option::Option<std::string::String> {
if entry_kind == crate::ENTRY_KIND_PROGRAM {
return None;
}
match entry_name {
"anchor_idl_instruction" => return Some("idl_management".to_string()),
"cpi_event" => return Some("cpi_transport".to_string()),
_ => return infer_event_family(entry_name, entry_kind),
}
}
fn infer_raydium_clmm_event_family(
entry_name: &str,
entry_kind: &str,
) -> std::option::Option<std::string::String> {
if entry_kind == crate::ENTRY_KIND_PROGRAM {
return None;
}
match entry_name {
"cpi_event" => return Some("cpi_transport".to_string()),
"create_personal_position_event" => return Some("position_open".to_string()),
"liquidity_calculate_event" => return Some("liquidity_calculation".to_string()),
"liquidity_change_event" => return Some("liquidity_change".to_string()),
"pool_created_event" => return Some("pool_create".to_string()),
"create_operation_account" => return Some("admin_config".to_string()),
"update_operation_account" => return Some("admin_config".to_string()),
"update_dynamic_fee_config" => return Some("admin_config".to_string()),
_ => return infer_event_family(entry_name, entry_kind),
}
}
fn infer_raydium_launchpad_event_family(
entry_name: &str,
entry_kind: &str,
) -> std::option::Option<std::string::String> {
if entry_kind == crate::ENTRY_KIND_PROGRAM {
return None;
}
match entry_name {
"buy_exact_in" => return Some("swap".to_string()),
"buy_exact_out" => return Some("swap".to_string()),
"sell_exact_in" => return Some("swap".to_string()),
"sell_exact_out" => return Some("swap".to_string()),
"trade_event" => return Some("swap".to_string()),
"pool_create_event" => return Some("pool_create".to_string()),
"initialize" => return Some("pool_create".to_string()),
"initialize_v2" => return Some("pool_create".to_string()),
"initialize_with_token_2022" => return Some("pool_create".to_string()),
"claim_creator_fee" => return Some("fee".to_string()),
"claim_platform_fee" => return Some("fee".to_string()),
"claim_platform_fee_from_vault" => return Some("fee".to_string()),
"collect_fee" => return Some("fee".to_string()),
"collect_migrate_fee" => return Some("fee".to_string()),
"claim_vested_event" => return Some("vesting".to_string()),
"claim_vested_token" => return Some("vesting".to_string()),
"create_platform_vesting_account" => return Some("vesting".to_string()),
"create_vesting_account" => return Some("vesting".to_string()),
"create_vesting_event" => return Some("vesting".to_string()),
"migrate_to_amm" => return Some("migration".to_string()),
"migrate_to_cpswap" => return Some("migration".to_string()),
"close_platform_global_access" => return Some("account_close".to_string()),
"create_config" => return Some("admin_config".to_string()),
"create_platform_config" => return Some("admin_config".to_string()),
"create_platform_global_access" => return Some("admin_config".to_string()),
"remove_platform_curve_param" => return Some("admin_config".to_string()),
"update_config" => return Some("admin_config".to_string()),
"update_platform_config" => return Some("admin_config".to_string()),
"update_platform_curve_param" => return Some("admin_config".to_string()),
"cpi_event" => return Some("cpi_transport".to_string()),
_ => return infer_event_family(entry_name, entry_kind),
}
}
fn infer_event_family(
entry_name: &str,
entry_kind: &str,
@@ -282,6 +452,12 @@ fn infer_event_family(
if normalized == "lp_change_event" {
return Some("liquidity".to_string());
}
if normalized == "cpi_event" {
return Some("cpi_transport".to_string());
}
if contains_any(normalized.as_str(), &["migrate", "migration", "graduate"]) {
return Some("migration".to_string());
}
if contains_any(normalized.as_str(), &["swap", "buy", "sell", "trade"]) {
return Some("swap".to_string());
}
@@ -416,10 +592,49 @@ fn contains_any(value: &str, needles: &[&str]) -> bool {
return false;
}
fn raydium_launchpad_local_entry_is_known(entry_name: &str) -> bool {
match entry_name {
"buy_exact_in" => return true,
"buy_exact_out" => return true,
"close_platform_global_access" => return true,
"claim_creator_fee" => return true,
"claim_platform_fee" => return true,
"claim_platform_fee_from_vault" => return true,
"claim_vested_event" => return true,
"claim_vested_token" => return true,
"collect_fee" => return true,
"collect_migrate_fee" => return true,
"create_config" => return true,
"create_platform_config" => return true,
"cpi_event" => return true,
"create_platform_vesting_account" => return true,
"create_platform_global_access" => return true,
"create_vesting_account" => return true,
"create_vesting_event" => return true,
"initialize" => return true,
"initialize_v2" => return true,
"initialize_with_token_2022" => return true,
"migrate_to_amm" => return true,
"migrate_to_cpswap" => return true,
"pool_create_event" => return true,
"remove_platform_curve_param" => return true,
"sell_exact_in" => return true,
"sell_exact_out" => return true,
"trade_event" => return true,
"update_config" => return true,
"update_platform_config" => return true,
"update_platform_curve_param" => return true,
_ => return false,
}
}
pub(crate) fn known_local_event_kind(
decoder_code: &str,
entry_name: &str,
) -> std::option::Option<std::string::String> {
if decoder_code == "raydium_launchpad" && raydium_launchpad_local_entry_is_known(entry_name) {
return Some(format!("raydium_launchpad.{}", entry_name));
}
match (decoder_code, entry_name) {
("raydium_cpmm", "swap_base_input") => {
return Some("raydium_cpmm.swap_base_input".to_string());
@@ -453,6 +668,10 @@ pub(crate) fn known_local_event_kind(
("raydium_cpmm", "lp_change_event") => {
return Some("raydium_cpmm.lp_change_event".to_string());
},
("raydium_cpmm", "cpi_event") => return Some("raydium_cpmm.cpi_event".to_string()),
("raydium_cpmm", "anchor_idl_instruction") => {
return Some("raydium_cpmm.anchor_idl_instruction".to_string());
},
("raydium_cpmm", "swap_event") => return Some("raydium_cpmm.swap_event".to_string()),
("raydium_cpmm", "update_amm_config") => {
return Some("raydium_cpmm.update_amm_config".to_string());
@@ -461,6 +680,38 @@ pub(crate) fn known_local_event_kind(
return Some("raydium_cpmm.update_pool_status".to_string());
},
("raydium_cpmm", "withdraw") => return Some("raydium_cpmm.withdraw".to_string()),
("raydium_clmm", "cpi_event") => return Some("raydium_clmm.cpi_event".to_string()),
("raydium_clmm", "collect_personal_fee_event") => {
return Some("raydium_clmm.collect_personal_fee_event".to_string());
},
("raydium_clmm", "collect_protocol_fee_event") => {
return Some("raydium_clmm.collect_protocol_fee_event".to_string());
},
("raydium_clmm", "config_change_event") => {
return Some("raydium_clmm.config_change_event".to_string());
},
("raydium_clmm", "create_personal_position_event") => {
return Some("raydium_clmm.create_personal_position_event".to_string());
},
("raydium_clmm", "decrease_liquidity_event") => {
return Some("raydium_clmm.decrease_liquidity_event".to_string());
},
("raydium_clmm", "increase_liquidity_event") => {
return Some("raydium_clmm.increase_liquidity_event".to_string());
},
("raydium_clmm", "liquidity_calculate_event") => {
return Some("raydium_clmm.liquidity_calculate_event".to_string());
},
("raydium_clmm", "liquidity_change_event") => {
return Some("raydium_clmm.liquidity_change_event".to_string());
},
("raydium_clmm", "pool_created_event") => {
return Some("raydium_clmm.pool_created_event".to_string());
},
("raydium_clmm", "swap_event") => return Some("raydium_clmm.swap_event".to_string()),
("raydium_clmm", "update_reward_infos_event") => {
return Some("raydium_clmm.update_reward_infos_event".to_string());
},
("raydium_clmm", "close_limit_order") => {
return Some("raydium_clmm.close_limit_order".to_string());
},
@@ -545,6 +796,9 @@ pub(crate) fn known_local_event_kind(
("raydium_clmm", "update_amm_config") => {
return Some("raydium_clmm.update_amm_config".to_string());
},
("raydium_clmm", "update_dynamic_fee_config") => {
return Some("raydium_clmm.update_dynamic_fee_config".to_string());
},
("raydium_clmm", "update_operation_account") => {
return Some("raydium_clmm.update_operation_account".to_string());
},
@@ -605,6 +859,23 @@ mod tests {
super::infer_event_family("collect_creator_fee", crate::ENTRY_KIND_INSTRUCTION),
Some("fee".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_cpmm",
"anchor_idl_instruction",
crate::ENTRY_KIND_INSTRUCTION,
),
Some("idl_management".to_string())
);
assert_eq!(
super::infer_expected_db_target_for_entry(
"raydium_cpmm",
"anchor_idl_instruction",
Some("idl_management"),
crate::ENTRY_KIND_INSTRUCTION,
),
Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string())
);
}
#[test]
@@ -617,6 +888,38 @@ mod tests {
super::infer_event_family("create_dynamic_fee_config", crate::ENTRY_KIND_INSTRUCTION),
Some("admin_config".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_clmm",
"update_dynamic_fee_config",
crate::ENTRY_KIND_INSTRUCTION,
),
Some("admin_config".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_clmm",
"create_personal_position_event",
crate::ENTRY_KIND_EVENT,
),
Some("position_open".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_clmm",
"liquidity_calculate_event",
crate::ENTRY_KIND_EVENT,
),
Some("liquidity_calculation".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_clmm",
"liquidity_change_event",
crate::ENTRY_KIND_EVENT,
),
Some("liquidity_change".to_string())
);
assert_eq!(
super::infer_event_family(
"create_support_mint_associated",
@@ -652,6 +955,15 @@ mod tests {
super::infer_expected_db_target(Some("position_open"), crate::ENTRY_KIND_INSTRUCTION),
Some(crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS.to_string())
);
assert_eq!(
super::infer_expected_db_target_for_entry(
"raydium_clmm",
"open_position",
Some("position_open"),
crate::ENTRY_KIND_INSTRUCTION,
),
Some(crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string())
);
assert_eq!(
super::infer_expected_db_target(Some("position_close"), crate::ENTRY_KIND_INSTRUCTION),
Some(crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS.to_string())
@@ -676,6 +988,79 @@ mod tests {
super::known_local_event_kind("raydium_clmm", "decrease_limit_order"),
Some("raydium_clmm.decrease_limit_order".to_string())
);
assert_eq!(
super::known_local_event_kind("raydium_clmm", "update_dynamic_fee_config"),
Some("raydium_clmm.update_dynamic_fee_config".to_string())
);
assert_eq!(
super::known_local_event_kind("raydium_clmm", "cpi_event"),
Some("raydium_clmm.cpi_event".to_string())
);
assert_eq!(
super::known_local_event_kind("raydium_clmm", "pool_created_event"),
Some("raydium_clmm.pool_created_event".to_string())
);
}
#[test]
fn launchpad_swap_instructions_materialize_as_launch_events_without_duplicate_trades() {
assert_eq!(
super::known_local_event_kind("raydium_launchpad", "buy_exact_in"),
Some("raydium_launchpad.buy_exact_in".to_string())
);
assert_eq!(
super::known_local_event_kind("raydium_launchpad", "trade_event"),
Some("raydium_launchpad.trade_event".to_string())
);
assert_eq!(super::known_local_event_kind("raydium_launchpad", "program"), None);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_launchpad",
"pool_create_event",
crate::ENTRY_KIND_EVENT,
),
Some("pool_create".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_launchpad",
"claim_vested_event",
crate::ENTRY_KIND_EVENT,
),
Some("vesting".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_launchpad",
"create_platform_vesting_account",
crate::ENTRY_KIND_INSTRUCTION,
),
Some("vesting".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_launchpad",
"remove_platform_curve_param",
crate::ENTRY_KIND_INSTRUCTION,
),
Some("admin_config".to_string())
);
assert_eq!(
super::infer_event_family_for_entry(
"raydium_launchpad",
"cpi_event",
crate::ENTRY_KIND_INSTRUCTION,
),
Some("cpi_transport".to_string())
);
assert_eq!(
super::infer_expected_db_target_for_entry(
"raydium_launchpad",
"buy_exact_in",
Some("swap"),
crate::ENTRY_KIND_INSTRUCTION,
),
Some(crate::DexEventCoverageEntryDto::DB_TARGET_LAUNCH_EVENTS.to_string())
);
}
#[tokio::test]
@@ -716,6 +1101,24 @@ mod tests {
== Some(crate::DexEventCoverageEntryDto::DB_TARGET_LIQUIDITY_EVENTS.to_string())
&& row.local_event_kind == Some("raydium_cpmm.lp_change_event".to_string())
}));
assert!(rows.iter().any(|row| return {
row.entry_name == "cpi_event"
&& row.event_family == Some("cpi_transport".to_string())
&& row.expected_db_target
== Some(
crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string(),
)
&& row.local_event_kind == Some("raydium_cpmm.cpi_event".to_string())
}));
assert!(rows.iter().any(|row| return {
row.entry_name == "anchor_idl_instruction"
&& row.event_family == Some("idl_management".to_string())
&& row.expected_db_target
== Some(
crate::DexEventCoverageEntryDto::DB_TARGET_DECODED_EVENTS_ONLY.to_string(),
)
&& row.local_event_kind == Some("raydium_cpmm.anchor_idl_instruction".to_string())
}));
assert!(rows.iter().any(|row| return {
row.entry_name == "swap_event"
&& row.event_family == Some("swap".to_string())

View File

@@ -248,25 +248,25 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
catalog_enabled: true,
},
DexSupportMatrixEntry {
code: "raydium_launchlab",
code: "raydium_launchpad",
display_name: "Raydium LaunchLab / Launchpad",
family: "raydium",
version: "launchlab",
version: "launchpad",
surface_type: "launch",
surface_role: "launch_surface",
program_id: Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
program_id: Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
router_program_id: None,
program_id_status: "known",
observed: false,
decoded: false,
decoded: true,
materialized: false,
trade_candidate: false,
candle_candidate: false,
pair_candidate: true,
pool_candidate: true,
status: "planned",
status: "bootstrap",
confidence: "medium",
skip_reason: Some("decoder_and_materialization_not_enabled"),
skip_reason: Some("decoded_events_only_until_local_corpus"),
catalog_enabled: false,
},
DexSupportMatrixEntry {
@@ -2736,7 +2736,7 @@ mod tests {
"raydium_cpmm",
"raydium_clmm",
"raydium_amm_v4",
"raydium_launchlab",
"raydium_launchpad",
"raydium_liquidity_locking",
"meteora_dlmm",
"meteora_dlc",
@@ -2832,11 +2832,25 @@ mod tests {
assert_eq!(entry.skip_reason, Some("meteora_damm_v1_swap_without_amount_payload"));
}
#[test]
fn matrix_marks_raydium_launchpad_bootstrap_conservatively() {
let entry = match crate::dex_support_matrix_entry_by_code("raydium_launchpad") {
Some(entry) => entry,
None => panic!("expected raydium_launchpad matrix entry"),
};
assert_eq!(entry.status, "bootstrap");
assert!(entry.decoded);
assert!(!entry.materialized);
assert!(!entry.trade_candidate);
assert!(!entry.candle_candidate);
assert_eq!(entry.skip_reason, Some("decoded_events_only_until_local_corpus"));
}
#[test]
fn matrix_marks_launch_surfaces_as_launch_or_bonding_curve() {
let codes = [
"pump_fun",
"raydium_launchlab",
"raydium_launchpad",
"letsbonk",
"bonk_fun",
"bags",
@@ -2863,15 +2877,7 @@ mod tests {
#[test]
fn matrix_keeps_0_7_39_deferred_surfaces_non_trade_materialized() {
let codes = [
"raydium_launchlab",
"letsbonk",
"bonk_fun",
"bags",
"moonshot",
"moonit",
"boop_fun",
"believe",
"heaven",
"letsbonk", "bonk_fun", "bags", "moonshot", "moonit", "boop_fun", "believe", "heaven",
];
for code in codes {
let entry = match crate::dex_support_matrix_entry_by_code(code) {

View File

@@ -399,6 +399,20 @@ fn resolve_instruction_name(
};
return Some(name.to_string());
}
if program_id == crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID
|| decoder_code == Some("raydium_launchpad")
{
if discriminator_hex == "e445a52e51cb9a1d" {
return Some("raydium_launchpad.anchor_self_cpi_log".to_string());
}
let layout = crate::dex::raydium_launchpad::account_layout(discriminator_hex, usize::MAX);
let layout = match layout {
Some(layout) => layout,
None => return None,
};
return Some(format!("raydium_launchpad.{}", layout.instruction_name));
}
return None;
}

View File

@@ -12,7 +12,7 @@ struct BuiltinLaunchSurfaceSpec {
const BUILTIN_LAUNCH_SURFACE_SPECS: &[BuiltinLaunchSurfaceSpec] = &[
BuiltinLaunchSurfaceSpec {
code: "raydium_launchlab",
code: "raydium_launchpad",
name: "Raydium LaunchLab / Launchpad",
protocol_family: "raydium",
enabled: true,
@@ -984,7 +984,7 @@ mod tests {
};
assert_eq!(surface_ids.len(), 9);
let required_codes = [
"raydium_launchlab",
"raydium_launchpad",
"letsbonk",
"bonk_fun",
"bags",
@@ -1018,7 +1018,7 @@ mod tests {
let service = crate::LaunchOriginService::new(database.clone());
let register_result = service
.register_launch_surface_mapping(
"raydium_launchlab",
"raydium_launchpad",
Some("DbcDetectTokenA111"),
Some("DbcDetectConfig111"),
None,
@@ -1026,23 +1026,23 @@ mod tests {
)
.await;
if let Err(error) = register_result {
panic!("launchlab mapping registration must succeed: {}", error);
panic!("launchpad mapping registration must succeed: {}", error);
}
seed_decoded_meteora_dbc_event(database.clone(), "sig-launch-origin-launchlab-1").await;
seed_decoded_meteora_dbc_event(database.clone(), "sig-launch-origin-launchpad-1").await;
let result = service
.attribute_transaction_by_signature("sig-launch-origin-launchlab-1")
.attribute_transaction_by_signature("sig-launch-origin-launchpad-1")
.await;
let results = match result {
Ok(results) => results,
Err(error) => panic!("launchlab attribution must succeed: {}", error),
Err(error) => panic!("launchpad attribution must succeed: {}", error),
};
assert_eq!(results.len(), 1);
assert!(results[0].created_attribution);
let surface_result =
crate::query_launch_surfaces_get_by_code(database.as_ref(), "raydium_launchlab").await;
crate::query_launch_surfaces_get_by_code(database.as_ref(), "raydium_launchpad").await;
let surface = match surface_result {
Ok(Some(surface)) => surface,
Ok(None) => panic!("raydium_launchlab surface must exist"),
Ok(None) => panic!("raydium_launchpad surface must exist"),
Err(error) => panic!("surface fetch must succeed: {}", error),
};
assert_eq!(surface.id, Some(results[0].launch_surface_id));

View File

@@ -208,7 +208,7 @@ pub use constants::ED25519_PROGRAM_ID;
/// Feature program identifier. ("Feature111111111111111111111111111111111111").
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::feature::ID
pub use constants::FEATURE_PROGRAM_ID;
/// FluxBeam program id. ("FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X").
/// Moonshot token authority account observed on Solscan program id. ("FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X").
pub use constants::FLUXBEAM_PROGRAM_ID;
/// FusionAMM program id from Vybe supported DEX/AMM documentation.
pub use constants::FUSIONAMM_PROGRAM_ID;
@@ -278,10 +278,12 @@ 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.
/// Meteora Vault program id. ("MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG").
pub use constants::METEORA_VAULT_PROGRAM_ID;
/// Moonshot program id extracted from upstream Git decoder source.
pub use constants::MOONSHOT_PROGRAM_ID;
/// FluxBeam program id. ("7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q").
pub use constants::MOONSHOT_TOKEN_AUTHORITY_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.
@@ -325,8 +327,10 @@ 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 platform config account observed on Solscan. ("4Bu96XjU84XjPDSpveTVf6LYGCkfW5FK7SNkREWcEfV4").
pub use constants::RAYDIUM_LAUNCHPAD_PLATFORM_CONFIG_ACCOUNT_ID;
/// Raydium LaunchLab / Launchpad program id. ("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj").
pub use constants::RAYDIUM_LAUNCHLAB_PROGRAM_ID;
pub use constants::RAYDIUM_LAUNCHPAD_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").
@@ -345,6 +349,8 @@ pub use constants::SHARKY_PROGRAM_ID;
pub use constants::SOLAYER_RESTAKING_PROGRAM_ID;
/// SolFi v2 program id from Vybe supported DEX/AMM documentation.
pub use constants::SOLFI_V2_PROGRAM_ID;
/// Manual Solscan account-source inventory collected for post-`0.7.50` DEX discovery.
pub use constants::SOLSCAN_ACCOUNT_SOURCES;
/// SPL Token-2022 program identifier. ("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb").
/// @see solana_sdk::pubkey::Pubkey = spl_token_2022_interface::ID
pub use constants::SPL_TOKEN_2022_PROGRAM_ID;
@@ -405,6 +411,8 @@ pub use constants::SYSVAR_SLOT_HISTORY_PROGRAM_ID;
/// Sysvar Stake History program identifier. ("SysvarStakeHistory1111111111111111111111111").
/// @see solana_sdk::pubkey::Pubkey = solana_sdk_ids::sysvar::stake_history::ID
pub use constants::SYSVAR_STAKE_HISTORY_PROGRAM_ID;
/// One Solscan account source collected during manual DEX/program inventory.
pub use constants::SolscanAccountSource;
/// Canonical Solana USDC mint identifier.
pub use constants::USDC_MINT_ID;
/// Canonical Solana USDT mint identifier.
@@ -664,6 +672,10 @@ pub use db::SwapDto;
pub use db::SwapEntity;
/// Swap side relative to the normalized base token of the pair.
pub use db::SwapTradeSide;
/// Application-facing normalized token-account event DTO.
pub use db::TokenAccountEventDto;
/// Persisted normalized token-account event row.
pub use db::TokenAccountEventEntity;
/// Application-facing normalized token burn event DTO.
pub use db::TokenBurnEventDto;
/// Persisted normalized token burn event row.
@@ -746,7 +758,10 @@ pub use db::query_dex_decoded_events_delete_locally_covered_upstream_instruction
pub use db::query_dex_decoded_events_delete_meteora_dlmm_anchor_swap_instruction_audits;
/// Deletes decoded DEX instruction audit rows related to one decoded instruction.
pub use db::query_dex_decoded_events_delete_related_instruction_audit;
/// Deletes Raydium CLMM instruction-audit rows for locally mapped CLMM instructions.
pub use db::query_dex_decoded_events_delete_replaced_raydium_clmm_instruction_audits;
/// Deletes Raydium CPMM instruction-audit rows already covered by local named rows.
pub use db::query_dex_decoded_events_delete_replaced_raydium_cpmm_instruction_audits;
/// Reads one decoded DEX event by its natural key.
pub use db::query_dex_decoded_events_get_by_key;
/// Returns the latest Pump.fun create payload associated with a token mint.
@@ -960,6 +975,8 @@ pub use db::query_reward_events_upsert;
pub use db::query_swaps_list_recent;
/// Inserts or updates one normalized swap row.
pub use db::query_swaps_upsert;
/// Inserts or updates one normalized token-account event row.
pub use db::query_token_account_events_upsert;
/// Lists recent token burn events ordered from newest to oldest.
pub use db::query_token_burn_events_list_recent;
/// Inserts or updates one normalized token burn event row.
@@ -1247,6 +1264,12 @@ pub use dex_event_classification::is_dex_position_close_event_kind;
pub use dex_event_classification::is_dex_position_open_event_kind;
/// Returns true for reward or emission DEX events.
pub use dex_event_classification::is_dex_reward_event_kind;
/// Returns true for token-account close events detected by DEX decoders.
pub use dex_event_classification::is_dex_token_account_close_event_kind;
/// Returns true for token-account creation events detected by DEX decoders.
pub use dex_event_classification::is_dex_token_account_create_event_kind;
/// Returns true for token-account lifecycle events detected by DEX decoders.
pub use dex_event_classification::is_dex_token_account_event_kind;
/// Returns true for token burn DEX events.
pub use dex_event_classification::is_dex_token_burn_event_kind;
/// Returns true for token mint DEX events.

View File

@@ -100,6 +100,8 @@ pub struct LocalPipelineReplayResult {
pub pool_admin_event_count: usize,
/// Total orderbook event materialization results returned by replayed non-trade calls.
pub orderbook_event_count: usize,
/// Total token-account event materialization results returned by replayed non-trade calls.
pub token_account_event_count: usize,
/// Total candle upsert results returned by replayed candle calls.
///
/// This is a replay write/result counter, not the number of distinct rows
@@ -367,6 +369,7 @@ impl LocalPipelineReplayService {
result.reward_event_count += non_trade_result.reward_event_count;
result.pool_admin_event_count += non_trade_result.pool_admin_event_count;
result.orderbook_event_count += non_trade_result.orderbook_event_count;
result.token_account_event_count += non_trade_result.token_account_event_count;
},
Err(error) => {
result.non_trade_materialization_error_count += 1;
@@ -521,6 +524,29 @@ impl LocalPipelineReplayService {
}
async fn refresh_event_coverage_best_effort(&self) {
let cpmm_cleanup_result =
crate::query_dex_decoded_events_delete_replaced_raydium_cpmm_instruction_audits(
self.database.as_ref(),
None,
)
.await;
match cpmm_cleanup_result {
Ok(deleted_count) => {
if deleted_count > 0 {
tracing::info!(
deleted_count = deleted_count,
"replaced Raydium CPMM instruction audits cleaned before dex event coverage refresh"
);
}
},
Err(error) => {
tracing::warn!(
error = %error,
"Raydium CPMM replaced instruction-audit cleanup failed before dex event coverage refresh"
);
},
}
let cleanup_result =
crate::query_dex_decoded_events_delete_replaced_raydium_clmm_instruction_audits(
self.database.as_ref(),
@@ -586,6 +612,46 @@ impl LocalPipelineReplayService {
},
}
let post_refresh_cpmm_cleanup_result =
crate::query_dex_decoded_events_delete_replaced_raydium_cpmm_instruction_audits(
self.database.as_ref(),
None,
)
.await;
match post_refresh_cpmm_cleanup_result {
Ok(deleted_count) => {
if deleted_count > 0 {
tracing::info!(
deleted_count = deleted_count,
"replaced Raydium CPMM instruction audits cleaned after dex event coverage refresh"
);
let second_refresh_result = coverage_service.refresh_local_counts(None).await;
match second_refresh_result {
Ok(second_refresh_result) => {
tracing::debug!(
upserted_entry_count = second_refresh_result.upserted_entry_count,
refreshed_entry_count = second_refresh_result.refreshed_entry_count,
summary_count = second_refresh_result.summaries.len(),
"dex event coverage refreshed after Raydium CPMM instruction-audit cleanup"
);
},
Err(error) => {
tracing::warn!(
error = %error,
"dex event coverage refresh failed after Raydium CPMM instruction-audit cleanup"
);
},
}
}
},
Err(error) => {
tracing::warn!(
error = %error,
"Raydium CPMM replaced instruction-audit cleanup failed after dex event coverage refresh"
);
},
}
let post_refresh_upstream_cleanup_result =
crate::query_dex_decoded_events_delete_locally_covered_upstream_instruction_matches(
self.database.as_ref(),

File diff suppressed because it is too large Load Diff

View File

@@ -115,6 +115,44 @@ pub(crate) async fn resolve_trade_amounts(
return Err(error);
}
}
let has_payload_trade_side = crate::trade_amount_resolution::extract_string_by_candidate_keys(
input.payload,
&["tradeSide", "trade_side"],
)
.is_some();
if input.decoded_event.event_kind == "raydium_launchpad.trade_event"
&& (base_amount_raw.is_none()
|| quote_amount_raw.is_none()
|| (!has_payload_trade_side && resolved_trade_side.is_none()))
{
let resolution_result =
crate::trade_amount_resolution::apply_raydium_launchpad_sibling_instruction_amount_fallback(
input,
&mut base_amount_raw,
&mut quote_amount_raw,
&mut resolved_trade_side,
)
.await;
if let Err(error) = resolution_result {
return Err(error);
}
}
if input.decoded_event.event_kind.starts_with("raydium_launchpad.")
&& (base_amount_raw.is_none()
|| quote_amount_raw.is_none()
|| price_quote_per_base.is_none())
{
let resolution_result =
crate::trade_amount_resolution::apply_raydium_launchpad_amount_fallback(
input,
&mut base_amount_raw,
&mut quote_amount_raw,
&mut price_quote_per_base,
);
if let Err(error) = resolution_result {
return Err(error);
}
}
if input.decoded_event.event_kind.starts_with("raydium_amm_v4.")
&& (base_amount_raw.is_none() || quote_amount_raw.is_none())
{
@@ -504,6 +542,223 @@ async fn apply_pump_swap_amount_fallbacks(
return Ok(());
}
fn apply_raydium_launchpad_amount_fallback(
input: &crate::trade_amount_resolution::TradeAmountResolutionInput<'_>,
base_amount_raw: &mut std::option::Option<std::string::String>,
quote_amount_raw: &mut std::option::Option<std::string::String>,
price_quote_per_base: &mut std::option::Option<f64>,
) -> Result<(), crate::Error> {
if base_amount_raw.is_some() && quote_amount_raw.is_some() && price_quote_per_base.is_some() {
return Ok(());
}
let transaction_value_result =
crate::trade_pump_swap_amounts::build_transaction_value_with_meta_json(
input.transaction.transaction_json.as_str(),
input.transaction.meta_json.as_deref(),
);
let transaction_value = match transaction_value_result {
Ok(transaction_value) => transaction_value,
Err(error) => return Err(error),
};
let fallback_amounts = match (input.base_token_mint, input.quote_token_mint) {
(Some(base_mint), Some(quote_mint)) => {
crate::trade_pump_swap_amounts::try_build_pump_swap_trade_amounts_from_token_balance_deltas(
&transaction_value,
base_mint,
quote_mint,
)
},
_ => None,
};
let fallback_amounts = match fallback_amounts {
Some(fallback_amounts) => fallback_amounts,
None => return Ok(()),
};
if base_amount_raw.is_none() {
*base_amount_raw = crate::trade_pump_swap_amounts::convert_ui_amount_to_raw_string(
fallback_amounts.base_amount,
input.base_token_decimals,
);
}
if quote_amount_raw.is_none() {
*quote_amount_raw = crate::trade_pump_swap_amounts::convert_ui_amount_to_raw_string(
fallback_amounts.quote_amount,
input.quote_token_decimals,
);
}
if price_quote_per_base.is_none() {
*price_quote_per_base = Some(fallback_amounts.price_quote_per_base);
}
tracing::debug!(
event_kind = %input.decoded_event.event_kind,
pool_account = ?input.decoded_event.pool_account,
decoded_event_id = ?input.decoded_event.id,
base_mint = ?input.base_token_mint,
quote_mint = ?input.quote_token_mint,
base_amount_raw = ?base_amount_raw,
quote_amount_raw = ?quote_amount_raw,
price_quote_per_base = ?price_quote_per_base,
"raydium_launchpad trade amounts recovered from transaction token balance deltas"
);
return Ok(());
}
async fn apply_raydium_launchpad_sibling_instruction_amount_fallback(
input: &crate::trade_amount_resolution::TradeAmountResolutionInput<'_>,
base_amount_raw: &mut std::option::Option<std::string::String>,
quote_amount_raw: &mut std::option::Option<std::string::String>,
resolved_trade_side: &mut std::option::Option<crate::SwapTradeSide>,
) -> Result<(), crate::Error> {
if base_amount_raw.is_some() && quote_amount_raw.is_some() && resolved_trade_side.is_some() {
return Ok(());
}
let amount_in_raw = crate::trade_amount_resolution::extract_amount_string(
input.payload,
&["amountInRaw", "amount_in_raw", "amountIn", "amount_in"],
);
let amount_out_raw = crate::trade_amount_resolution::extract_amount_string(
input.payload,
&["amountOutRaw", "amount_out_raw", "amountOut", "amount_out"],
);
let amount_in_raw = match amount_in_raw {
Some(amount_in_raw) => amount_in_raw,
None => return Ok(()),
};
let amount_out_raw = match amount_out_raw {
Some(amount_out_raw) => amount_out_raw,
None => return Ok(()),
};
let sibling_side_result =
crate::trade_amount_resolution::resolve_raydium_launchpad_sibling_instruction_side(input)
.await;
let sibling_side = match sibling_side_result {
Ok(sibling_side) => sibling_side,
Err(error) => return Err(error),
};
let sibling_side = match sibling_side {
Some(sibling_side) => sibling_side,
None => return Ok(()),
};
crate::trade_amount_resolution::apply_raydium_launchpad_side_amount_mapping(
sibling_side,
amount_in_raw.as_str(),
amount_out_raw.as_str(),
base_amount_raw,
quote_amount_raw,
resolved_trade_side,
);
tracing::debug!(
event_kind = %input.decoded_event.event_kind,
pool_account = ?input.decoded_event.pool_account,
decoded_event_id = ?input.decoded_event.id,
transaction_signature = %input.transaction.signature,
base_amount_raw = ?base_amount_raw,
quote_amount_raw = ?quote_amount_raw,
resolved_trade_side = ?resolved_trade_side,
"raydium_launchpad trade amounts recovered from sibling swap instruction"
);
return Ok(());
}
async fn resolve_raydium_launchpad_sibling_instruction_side(
input: &crate::trade_amount_resolution::TradeAmountResolutionInput<'_>,
) -> Result<std::option::Option<crate::SwapTradeSide>, crate::Error> {
let decoded_events_result = crate::query_dex_decoded_events_list_by_transaction_id(
input.database,
input.decoded_event.transaction_id,
)
.await;
let decoded_events = match decoded_events_result {
Ok(decoded_events) => decoded_events,
Err(error) => return Err(error),
};
let mut resolved_side = None;
for decoded_event in decoded_events {
if decoded_event.id == input.decoded_event.id {
continue;
}
if decoded_event.protocol_name != "raydium_launchpad" {
continue;
}
if decoded_event.pool_account.as_deref() != Some(input.pool_address) {
continue;
}
let side = crate::trade_amount_resolution::raydium_launchpad_instruction_side(
decoded_event.event_kind.as_str(),
);
let side = match side {
Some(side) => side,
None => continue,
};
match resolved_side {
Some(existing_side) => {
if existing_side != side {
tracing::debug!(
transaction_signature = %input.transaction.signature,
pool_account = %input.pool_address,
decoded_event_id = ?input.decoded_event.id,
existing_side = ?existing_side,
conflicting_side = ?side,
"raydium_launchpad sibling swap instruction side is ambiguous"
);
return Ok(None);
}
},
None => resolved_side = Some(side),
}
}
return Ok(resolved_side);
}
fn raydium_launchpad_instruction_side(
event_kind: &str,
) -> std::option::Option<crate::SwapTradeSide> {
match event_kind {
"raydium_launchpad.buy_exact_in" | "raydium_launchpad.buy_exact_out" => {
return Some(crate::SwapTradeSide::BuyBase);
},
"raydium_launchpad.sell_exact_in" | "raydium_launchpad.sell_exact_out" => {
return Some(crate::SwapTradeSide::SellBase);
},
_ => return None,
}
}
fn apply_raydium_launchpad_side_amount_mapping(
side: crate::SwapTradeSide,
amount_in_raw: &str,
amount_out_raw: &str,
base_amount_raw: &mut std::option::Option<std::string::String>,
quote_amount_raw: &mut std::option::Option<std::string::String>,
resolved_trade_side: &mut std::option::Option<crate::SwapTradeSide>,
) {
match side {
crate::SwapTradeSide::BuyBase => {
if base_amount_raw.is_none() {
*base_amount_raw = Some(amount_out_raw.to_string());
}
if quote_amount_raw.is_none() {
*quote_amount_raw = Some(amount_in_raw.to_string());
}
if resolved_trade_side.is_none() {
*resolved_trade_side = Some(crate::SwapTradeSide::BuyBase);
}
},
crate::SwapTradeSide::SellBase => {
if base_amount_raw.is_none() {
*base_amount_raw = Some(amount_in_raw.to_string());
}
if quote_amount_raw.is_none() {
*quote_amount_raw = Some(amount_out_raw.to_string());
}
if resolved_trade_side.is_none() {
*resolved_trade_side = Some(crate::SwapTradeSide::SellBase);
}
},
crate::SwapTradeSide::Unknown => {},
}
}
fn apply_pump_fun_amount_fallback(
input: &crate::trade_amount_resolution::TradeAmountResolutionInput<'_>,
base_amount_raw: &mut std::option::Option<std::string::String>,
@@ -1676,6 +1931,66 @@ mod tests {
assert_eq!(side, Some(crate::SwapTradeSide::SellBase));
}
#[test]
fn raydium_launchpad_buy_instruction_maps_amount_in_out_to_base_quote() {
let mut base_amount_raw = None;
let mut quote_amount_raw = None;
let mut resolved_trade_side = None;
super::apply_raydium_launchpad_side_amount_mapping(
crate::SwapTradeSide::BuyBase,
"15000",
"262584872",
&mut base_amount_raw,
&mut quote_amount_raw,
&mut resolved_trade_side,
);
assert_eq!(base_amount_raw, Some("262584872".to_string()));
assert_eq!(quote_amount_raw, Some("15000".to_string()));
assert_eq!(resolved_trade_side, Some(crate::SwapTradeSide::BuyBase));
}
#[test]
fn raydium_launchpad_sell_instruction_maps_amount_in_out_to_base_quote() {
let mut base_amount_raw = None;
let mut quote_amount_raw = None;
let mut resolved_trade_side = None;
super::apply_raydium_launchpad_side_amount_mapping(
crate::SwapTradeSide::SellBase,
"11093407717995",
"43968050",
&mut base_amount_raw,
&mut quote_amount_raw,
&mut resolved_trade_side,
);
assert_eq!(base_amount_raw, Some("11093407717995".to_string()));
assert_eq!(quote_amount_raw, Some("43968050".to_string()));
assert_eq!(resolved_trade_side, Some(crate::SwapTradeSide::SellBase));
}
#[test]
fn raydium_launchpad_instruction_side_maps_exact_in_and_exact_out_variants() {
assert_eq!(
super::raydium_launchpad_instruction_side("raydium_launchpad.buy_exact_in"),
Some(crate::SwapTradeSide::BuyBase)
);
assert_eq!(
super::raydium_launchpad_instruction_side("raydium_launchpad.buy_exact_out"),
Some(crate::SwapTradeSide::BuyBase)
);
assert_eq!(
super::raydium_launchpad_instruction_side("raydium_launchpad.sell_exact_in"),
Some(crate::SwapTradeSide::SellBase)
);
assert_eq!(
super::raydium_launchpad_instruction_side("raydium_launchpad.sell_exact_out"),
Some(crate::SwapTradeSide::SellBase)
);
assert_eq!(
super::raydium_launchpad_instruction_side("raydium_launchpad.collect_fee"),
None
);
}
#[test]
fn failed_transaction_does_not_infer_trade_side() {
let transaction_json = transaction_json_with_vaults("base_vault", "quote_vault");

View File

@@ -13,8 +13,37 @@ const UPSTREAM_GIT_DISCRIMINATOR_NOTES: &str = "entry name and discriminator ext
const UPSTREAM_GIT_ALIAS_PROGRAM_NOTES: &str = "upstream Git decoder name kept as a discovery alias; program id and discriminator rows are represented by the canonical decoder entry to avoid duplicate registry keys";
const RAYDIUM_IDL_SOURCE_REPO: &str = "raydium-io/raydium-idl";
const MANUAL_SOLSCAN_SOURCE_REPO: &str = "manual-solscan";
const RAYDIUM_IDL_DISCRIMINATOR_NOTES: &str = "entry name and discriminator extracted from Raydium official IDL snapshot; not corpus-verified; no trade/candle/materialization proof";
const MANUAL_SOLSCAN_DISCRIMINATOR_NOTES: &str = "entry name and discriminator derived from local corpus plus manual Solscan transaction-log inspection; no trade/candle/materialization proof";
const fn manual_solscan_discriminator_entry(
decoder_code: &'static str,
program_id: std::option::Option<&'static str>,
program_family: &'static str,
surface_kind: &'static str,
entry_kind: &'static str,
entry_name: &'static str,
discriminator_hex: &'static str,
discriminator_len: u16,
source_path: &'static str,
) -> crate::UpstreamRegistryEntry {
return crate::UpstreamRegistryEntry {
source_repo: Some(MANUAL_SOLSCAN_SOURCE_REPO),
source_path: Some(source_path),
decoder_code,
program_id,
program_family,
surface_kind,
entry_kind,
entry_name,
discriminator_hex: Some(discriminator_hex),
discriminator_len: Some(discriminator_len),
proof_status: crate::PROOF_STATUS_UPSTREAM_GIT_UNVERIFIED,
notes: MANUAL_SOLSCAN_DISCRIMINATOR_NOTES,
};
}
const fn raydium_idl_discriminator_entry(
decoder_code: &'static str,
@@ -453,8 +482,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-cpmm-decoder/src/lib.rs",
),
upstream_git_program_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
"decoders/raydium-launchpad-decoder/src/lib.rs",
@@ -619,6 +648,17 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/meteora-damm-v2-decoder/src/instructions/claim_reward.rs",
),
upstream_git_discriminator_entry(
"meteora_damm_v2",
Some(crate::METEORA_DAMM_V2_PROGRAM_ID),
"meteora",
"amm",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"bcd8a66c1aa68eb6",
8,
"decoders/meteora-damm-v2-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"meteora_damm_v2",
Some(crate::METEORA_DAMM_V2_PROGRAM_ID),
@@ -663,17 +703,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/meteora-damm-v2-decoder/src/instructions/close_token_badge.rs",
),
upstream_git_discriminator_entry(
"meteora_damm_v2",
Some(crate::METEORA_DAMM_V2_PROGRAM_ID),
"meteora",
"amm",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"bcd8a66c1aa68eb6",
8,
"decoders/meteora-damm-v2-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"meteora_damm_v2",
Some(crate::METEORA_DAMM_V2_PROGRAM_ID),
@@ -1961,17 +1990,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/dflow-aggregator-v4-decoder/src/instructions/close_order.rs",
),
upstream_git_discriminator_entry(
"dflow_aggregator_v4",
Some(crate::DFLOW_AGGREGATOR_V4_PROGRAM_ID),
"dflow",
"aggregator",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/dflow-aggregator-v4-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"dflow_aggregator_v4",
Some(crate::DFLOW_AGGREGATOR_V4_PROGRAM_ID),
@@ -5030,17 +5048,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/jupiter-lend-decoder/src/instructions/collect_revenue.rs",
),
upstream_git_discriminator_entry(
"jupiter_lend",
Some(crate::JUPITER_LEND_PROGRAM_ID),
"jupiter",
"lending",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/jupiter-lend-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"jupiter_lend",
Some(crate::JUPITER_LEND_PROGRAM_ID),
@@ -5503,17 +5510,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/jupiter-swap-decoder/src/instructions/close_token.rs",
),
upstream_git_discriminator_entry(
"jupiter_swap",
Some(crate::JUPITER_SWAP_PROGRAM_ID),
"jupiter",
"aggregator",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/jupiter-swap-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"jupiter_swap",
Some(crate::JUPITER_SWAP_PROGRAM_ID),
@@ -8110,17 +8106,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/onchain-labs-dex-v2-decoder/src/instructions/claim.rs",
),
upstream_git_discriminator_entry(
"onchain_labs_dex_v2",
Some(crate::ONCHAIN_LABS_DEX_V2_PROGRAM_ID),
"onchain_labs",
"amm",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/onchain-labs-dex-v2-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"onchain_labs_dex_v2",
Some(crate::ONCHAIN_LABS_DEX_V2_PROGRAM_ID),
@@ -10123,17 +10108,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/pump-fees-decoder/src/instructions/claim_social_fee_pda.rs",
),
upstream_git_discriminator_entry(
"pump_fees",
Some(crate::PUMP_FEES_PROGRAM_ID),
"pump",
"fee_program",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/pump-fees-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"pump_fees",
Some(crate::PUMP_FEES_PROGRAM_ID),
@@ -10574,17 +10548,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/pump-swap-decoder/src/instructions/collect_coin_creator_fee.rs",
),
upstream_git_discriminator_entry(
"pump_swap",
Some(crate::PUMP_SWAP_PROGRAM_ID),
"pump",
"amm",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/pump-swap-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"pump_swap",
Some(crate::PUMP_SWAP_PROGRAM_ID),
@@ -11113,17 +11076,6 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/pumpfun-decoder/src/instructions/collect_creator_fee.rs",
),
upstream_git_discriminator_entry(
"pump_fun",
Some(crate::PUMP_FUN_PROGRAM_ID),
"pump",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/pumpfun-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"pump_fun",
Some(crate::PUMP_FUN_PROGRAM_ID),
@@ -11795,6 +11747,17 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
1,
"decoders/raydium-amm-v4-decoder/src/instructions/withdraw_srm.rs",
),
upstream_git_discriminator_entry(
"raydium_clmm",
Some(crate::RAYDIUM_CLMM_PROGRAM_ID),
"raydium",
"clmm",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/raydium-clmm-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"raydium_clmm",
Some(crate::RAYDIUM_CLMM_PROGRAM_ID),
@@ -12235,6 +12198,17 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/raydium-clmm-decoder/src/instructions/update_amm_config.rs",
),
upstream_git_discriminator_entry(
"raydium_clmm",
Some(crate::RAYDIUM_CLMM_PROGRAM_ID),
"raydium",
"clmm",
crate::ENTRY_KIND_INSTRUCTION,
"update_dynamic_fee_config",
"0707500802c784f0",
8,
"decoders/raydium-clmm-decoder/src/instructions/update_dynamic_fee_config.rs",
),
upstream_git_discriminator_entry(
"raydium_clmm",
Some(crate::RAYDIUM_CLMM_PROGRAM_ID),
@@ -12279,6 +12253,17 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/raydium-clmm-decoder/src/instructions/update_reward_infos_event.rs",
),
manual_solscan_discriminator_entry(
"raydium_cpmm",
Some(crate::RAYDIUM_CPMM_PROGRAM_ID),
"raydium",
"amm",
crate::ENTRY_KIND_INSTRUCTION,
"anchor_idl_instruction",
"40f4bc78a7e9690a",
8,
"solscan/tx/Hi6MkRTkcgwBi1WpiiudGPHKLuaKXKamNgVsy6YqoQeMRnrkpGjNx75ymrY59tJ3NN1GCn6nrndz9thMmwALLcY",
),
upstream_git_discriminator_entry(
"raydium_cpmm",
Some(crate::RAYDIUM_CPMM_PROGRAM_ID),
@@ -12323,6 +12308,17 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/raydium-cpmm-decoder/src/instructions/collect_protocol_fee.rs",
),
upstream_git_discriminator_entry(
"raydium_cpmm",
Some(crate::RAYDIUM_CPMM_PROGRAM_ID),
"raydium",
"amm",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/raydium-cpmm-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"raydium_cpmm",
Some(crate::RAYDIUM_CPMM_PROGRAM_ID),
@@ -12456,8 +12452,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-cpmm-decoder/src/instructions/withdraw.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12467,8 +12463,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/buy_exact_in.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12478,8 +12474,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/buy_exact_out.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12489,8 +12485,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/claim_creator_fee.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12500,8 +12496,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/claim_platform_fee.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12511,8 +12507,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/claim_platform_fee_from_vault.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_EVENT,
@@ -12522,8 +12518,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/claim_vested_event.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12533,8 +12529,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/claim_vested_token.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12544,8 +12540,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/collect_fee.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12555,8 +12551,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/collect_migrate_fee.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12566,8 +12562,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/create_config.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12577,8 +12573,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/create_platform_config.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12588,8 +12584,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/create_vesting_account.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_EVENT,
@@ -12599,8 +12595,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/create_vesting_event.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12610,8 +12606,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/initialize.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12621,8 +12617,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/initialize_v2.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12632,8 +12628,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/initialize_with_token_2022.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12643,8 +12639,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/migrate_to_amm.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12654,8 +12650,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/migrate_to_cpswap.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_EVENT,
@@ -12665,8 +12661,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/pool_create_event.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12676,8 +12672,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/remove_platform_curve_param.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12687,8 +12683,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/sell_exact_in.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12698,8 +12694,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/sell_exact_out.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_EVENT,
@@ -12709,8 +12705,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/trade_event.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12720,8 +12716,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/update_config.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12731,8 +12727,8 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
"decoders/raydium-launchpad-decoder/src/instructions/update_platform_config.rs",
),
upstream_git_discriminator_entry(
"raydium_launchlab",
Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
@@ -12741,6 +12737,50 @@ pub(crate) const UPSTREAM_REGISTRY_ENTRIES: &[crate::UpstreamRegistryEntry] = &[
8,
"decoders/raydium-launchpad-decoder/src/instructions/update_platform_curve_param.rs",
),
upstream_git_discriminator_entry(
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
"close_platform_global_access",
"7bb4b8816fb9bb3b",
8,
"decoders/raydium-launchpad-decoder/src/instructions/close_platform_global_access.rs",
),
upstream_git_discriminator_entry(
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
"create_platform_global_access",
"a25b92c75d85eaed",
8,
"decoders/raydium-launchpad-decoder/src/instructions/create_platform_global_access.rs",
),
upstream_git_discriminator_entry(
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
"create_platform_vesting_account",
"9247ad4562130f6a",
8,
"decoders/raydium-launchpad-decoder/src/instructions/create_platform_vesting_account.rs",
),
upstream_git_discriminator_entry(
"raydium_launchpad",
Some(crate::RAYDIUM_LAUNCHPAD_PROGRAM_ID),
"raydium",
"launch",
crate::ENTRY_KIND_INSTRUCTION,
"cpi_event",
"e445a52e51cb9a1d",
8,
"decoders/raydium-launchpad-decoder/src/instructions/cpi_event.rs",
),
upstream_git_discriminator_entry(
"raydium_liquidity_locking",
Some(crate::RAYDIUM_LIQUIDITY_LOCKING_PROGRAM_ID),

View File

@@ -327,7 +327,7 @@ mod tests {
"raydium_amm_v4",
"raydium_clmm",
"raydium_cpmm",
"raydium_launchlab",
"raydium_launchpad",
"raydium_liquidity_locking",
"raydium_stable_swap",
"orca_whirlpools",