This commit is contained in:
2026-05-19 11:48:32 +02:00
parent 3da01156a0
commit fad7ec5107
19 changed files with 218 additions and 64 deletions

View File

@@ -69,4 +69,4 @@
0.7.36 - Consolidation de la famille Meteora : corpus mixte `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlmm`, correction des discriminants DAMM v2 / DBC, validation du profil `0.7.36_meteora_family_consolidation`, et reclassement explicite des swaps DAMM v2 / DBC sans payload montant/prix en `non_actionable_trade` afin déviter tout trade/candle artificiel. 0.7.36 - Consolidation de la famille Meteora : corpus mixte `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlmm`, correction des discriminants DAMM v2 / DBC, validation du profil `0.7.36_meteora_family_consolidation`, et reclassement explicite des swaps DAMM v2 / DBC sans payload montant/prix en `non_actionable_trade` afin déviter tout trade/candle artificiel.
0.7.37 - Première tranche metadata/catalog : ajout du profil `0.7.37_token_metadata_catalog_enrichment`, exposition des compteurs metadata dans diagnostics/validation et raccordement UI Demo Pipeline 2 sans rendre les metadata manquantes bloquantes. 0.7.37 - Première tranche metadata/catalog : ajout du profil `0.7.37_token_metadata_catalog_enrichment`, exposition des compteurs metadata dans diagnostics/validation et raccordement UI Demo Pipeline 2 sans rendre les metadata manquantes bloquantes.
0.7.38 - Priorisation des metadata manquantes : ajout du profil `0.7.38_token_metadata_gap_prioritization`, samples `tokenMetadataGapSamples`, priorités tradable/quote/catalog, raccordement UI Demo Pipeline 2 et maintien du caractère non bloquant des metadata incomplètes. 0.7.38 - Priorisation des metadata manquantes : ajout du profil `0.7.38_token_metadata_gap_prioritization`, samples `tokenMetadataGapSamples`, priorités tradable/quote/catalog, raccordement UI Demo Pipeline 2 et maintien du caractère non bloquant des metadata incomplètes.
0.7.39 - Tranche sûre launch surfaces : ensemencement contrôlé des origins LaunchLab/Launchpad/LetsBonk/Bonk.fun/Bags/Moonshot/Moonit/Boop.fun/Believe, Heaven préparé mais désactivé, mappings génériques vérifiés, samples diagnostics `launchOriginSamples` / `poolOriginSamples`, profil `0.7.39_launch_surface_origin_baseline`, raccordement Demo Pipeline 2 et maintien de linvariant sans faux trade/candle ni program id fictif. 0.7.39 - Réorientation DEX-first : ajout du rôle stratégique `surfaceRole` dans la matrice DEX (`dex_effective`, `aggregator_router`, `launch_surface`, `to_verify`), profil `0.7.39_dex_first_effective_swap_surfaces`, ajout de `metaDAO` et `Printr` comme entrées `to_verify` sans `program_id`, maintien des launch surfaces en état différé et des invariants sans faux trade/candle ni program id fictif.

View File

@@ -114,7 +114,7 @@ La distinction de travail à partir de `0.7.39` est la suivante :
### 4.1. Matrice de travail ### 4.1. Matrice de travail
Depuis `0.7.29`, la matrice de support DEX est portée par `kb_lib/src/dex_support_matrix.rs`. Elle centralise le code interne, la famille, la version, le type de surface, les program ids vérifiés localement, le statut de support, les capacités actuelles et les raisons de skip. Depuis `0.7.29`, la matrice de support DEX est portée par `kb_lib/src/dex_support_matrix.rs`. Elle centralise le code interne, la famille, la version, le type technique de surface, le rôle stratégique de surface (`dex_effective`, `aggregator_router`, `launch_surface`, `to_verify`), les program ids vérifiés localement, le statut de support, les capacités actuelles et les raisons de skip.
Depuis `0.7.30`, les événements décodés reçoivent aussi une classification plus fine : `eventLifecycleKind`, `eventActionability` et `nonTradeUseful`. Cette classification sert aux diagnostics et prépare la matérialisation future des événements non-trade sans alimenter directement les trades/candles. Depuis `0.7.30`, les événements décodés reçoivent aussi une classification plus fine : `eventLifecycleKind`, `eventActionability` et `nonTradeUseful`. Cette classification sert aux diagnostics et prépare la matérialisation future des événements non-trade sans alimenter directement les trades/candles.

View File

@@ -787,7 +787,7 @@ Contraintes :
Réalisé : Réalisé :
- ajouter `kb_lib/src/dex_support_matrix.rs` comme source commune de metadata DEX/surfaces ; - ajouter `kb_lib/src/dex_support_matrix.rs` comme source commune de metadata DEX/surfaces ;
- exposer pour chaque entrée : code interne, famille, version, type de surface, program id connu ou à vérifier, support actuel, statut, confiance, raisons de skip et activation catalogue ; - exposer pour chaque entrée : code interne, famille, version, type technique de surface, rôle stratégique de surface, program id connu ou à vérifier, support actuel, statut, confiance, raisons de skip et activation catalogue ;
- raccorder `dex_catalog`, `transaction_classification` et `protocol_candidate_recording` à cette matrice ; - raccorder `dex_catalog`, `transaction_classification` et `protocol_candidate_recording` à cette matrice ;
- ajouter le profil `0.7.29_multi_dex_matrix_baseline` ; - ajouter le profil `0.7.29_multi_dex_matrix_baseline` ;
- exposer la matrice dans le rapport de validation local ; - exposer la matrice dans le rapport de validation local ;
@@ -947,9 +947,9 @@ Décision : `0.7.38` est clos. La clôture `0.7.38-B` conserve la logique de sta
### 6.071. Version `0.7.39` — Réorientation DEX-first et inventaire des DEX effectifs ### 6.071. Version `0.7.39` — Réorientation DEX-first et inventaire des DEX effectifs
Objectif : remplacer la priorité précédemment donnée aux launch surfaces par une consolidation des vrais DEX sur lesquels les swaps et événements de marché sont exécutés. Objectif : remplacer la priorité précédemment donnée aux launch surfaces par une consolidation des vrais DEX sur lesquels les swaps et événements de marché sont exécutés.
À faire : Réalisé :
- modifier la matrice DEX pour distinguer explicitement : `dex_effective`, `aggregator/router`, `launch_surface`, `to_verify` ; - modifier la matrice DEX pour distinguer explicitement les rôles `dex_effective`, `aggregator_router`, `launch_surface`, `to_verify` ;
- vérifier les DEX de swap principaux déjà connus : `pump_swap`, `raydium_cpmm`, `raydium_clmm`, `raydium_amm_v4`, `raydium_stable_swap`, `meteora_dlmm`, `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc`, `orca_whirlpools`, `fluxbeam`, `dexlab` ; - vérifier les DEX de swap principaux déjà connus : `pump_swap`, `raydium_cpmm`, `raydium_clmm`, `raydium_amm_v4`, `raydium_stable_swap`, `meteora_dlmm`, `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc`, `orca_whirlpools`, `fluxbeam`, `dexlab` ;
- ajouter `metaDAO` et `Printr` comme entrées `to_verify` dans la matrice, sans `program_id` tant quils ne sont pas prouvés ; - ajouter `metaDAO` et `Printr` comme entrées `to_verify` dans la matrice, sans `program_id` tant quils ne sont pas prouvés ;
- rechercher ou confirmer les `program_id` inconnus depuis les corpus locaux, les protocol candidates, DEX Screener, les explorateurs et les transactions résolues ; - rechercher ou confirmer les `program_id` inconnus depuis les corpus locaux, les protocol candidates, DEX Screener, les explorateurs et les transactions résolues ;

View File

@@ -166,7 +166,7 @@
<div class="mb-3"> <div class="mb-3">
<label for="demoPipeline2ValidationProfileSelect" class="form-label">Validation profile</label> <label for="demoPipeline2ValidationProfileSelect" class="form-label">Validation profile</label>
<select id="demoPipeline2ValidationProfileSelect" class="form-select"> <select id="demoPipeline2ValidationProfileSelect" class="form-select">
<option value="0.7.39_launch_surface_origin_baseline" selected>0.7.39 — launch surface origin baseline</option> <option value="0.7.39_dex_first_effective_swap_surfaces" selected>0.7.39 — DEX-first effective swap surfaces</option>
<option value="0.7.38_token_metadata_gap_prioritization">0.7.38 — token metadata gap prioritization</option> <option value="0.7.38_token_metadata_gap_prioritization">0.7.38 — token metadata gap prioritization</option>
<option value="0.7.37_token_metadata_catalog_enrichment">0.7.37 — token metadata/catalog enrichment</option> <option value="0.7.37_token_metadata_catalog_enrichment">0.7.37 — token metadata/catalog enrichment</option>
<option value="0.7.36_meteora_family_consolidation">0.7.36 — Meteora family consolidation</option> <option value="0.7.36_meteora_family_consolidation">0.7.36 — Meteora family consolidation</option>

View File

@@ -21,9 +21,13 @@ family: string,
*/ */
version: string, version: string,
/** /**
* Surface type: launch, bonding curve, AMM, CLMM, DLMM, router, aggregator or unknown. * Technical surface type: launch, bonding curve, AMM, CLMM, DLMM, router, aggregator or unknown.
*/ */
surfaceType: string, surfaceType: string,
/**
* Strategic surface role: dex_effective, aggregator_router, launch_surface or to_verify.
*/
surfaceRole: string,
/** /**
* Primary Solana program id, when verified in local constants or docs. * Primary Solana program id, when verified in local constants or docs.
*/ */

View File

@@ -225,8 +225,10 @@ pub(crate) struct DemoPipeline2DexSupportMatrixEntry {
pub family: std::string::String, pub family: std::string::String,
/// Protocol version or `unknown` when not verified locally. /// Protocol version or `unknown` when not verified locally.
pub version: std::string::String, pub version: std::string::String,
/// Surface type: launch, bonding curve, AMM, CLMM, DLMM, router, aggregator or unknown. /// Technical surface type: launch, bonding curve, AMM, CLMM, DLMM, router, aggregator or unknown.
pub surface_type: std::string::String, pub surface_type: std::string::String,
/// Strategic surface role: dex_effective, aggregator_router, launch_surface or to_verify.
pub surface_role: std::string::String,
/// Primary Solana program id, when verified in local constants or docs. /// Primary Solana program id, when verified in local constants or docs.
pub program_id: std::option::Option<std::string::String>, pub program_id: std::option::Option<std::string::String>,
/// Optional router program id, when this entry uses a distinct router. /// Optional router program id, when this entry uses a distinct router.
@@ -1263,7 +1265,7 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
let service = kb_lib::LocalPipelineValidationService::new(database.clone()); let service = kb_lib::LocalPipelineValidationService::new(database.clone());
let profile_code = match request { let profile_code = match request {
Some(request) => request.profile_code, Some(request) => request.profile_code,
None => "0.7.39_launch_surface_origin_baseline".to_string(), None => "0.7.39_dex_first_effective_swap_surfaces".to_string(),
}; };
let run_result = match profile_code.as_str() { let run_result = match profile_code.as_str() {
"0.7.27" | "0.7.27_dexes_non_regression" => { "0.7.27" | "0.7.27_dexes_non_regression" => {
@@ -1302,7 +1304,7 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
"0.7.38" | "0.7.38_token_metadata_gap_prioritization" => { "0.7.38" | "0.7.38_token_metadata_gap_prioritization" => {
service.validate_v0_7_38_current_database().await service.validate_v0_7_38_current_database().await
}, },
"0.7.39" | "0.7.39_launch_surface_origin_baseline" => { "0.7.39" | "0.7.39_dex_first_effective_swap_surfaces" | "0.7.39_launch_surface_origin_baseline" => {
service.validate_v0_7_39_current_database().await service.validate_v0_7_39_current_database().await
}, },
other => Err(kb_lib::Error::InvalidState(format!( other => Err(kb_lib::Error::InvalidState(format!(
@@ -1762,6 +1764,7 @@ fn demo_pipeline2_map_dex_support_matrix_entry(
family: entry.family, family: entry.family,
version: entry.version, version: entry.version,
surface_type: entry.surface_type, surface_type: entry.surface_type,
surface_role: entry.surface_role,
program_id: entry.program_id, program_id: entry.program_id,
router_program_id: entry.router_program_id, router_program_id: entry.router_program_id,
program_id_status: entry.program_id_status, program_id_status: entry.program_id_status,

View File

@@ -186,16 +186,16 @@ mod tests {
.expect("database init must succeed"); .expect("database init must succeed");
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
&database, &database,
&crate::DexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), &crate::DexDto::new("raydium_amm_v4".to_string(), "Raydium AMM v4".to_string(), None, None, true),
) )
.await .await
.expect("dex upsert must succeed"); .expect("dex upsert must succeed");
assert!(dex_id > 0); assert!(dex_id > 0);
let dex = crate::query_dexs_get_by_code(&database, "raydium") let dex = crate::query_dexs_get_by_code(&database, "raydium_amm_v4")
.await .await
.expect("get dex must succeed"); .expect("get dex must succeed");
assert!(dex.is_some()); assert!(dex.is_some());
assert_eq!(dex.expect("dex must exist").name, "Raydium"); assert_eq!(dex.expect("dex must exist").name, "Raydium AMM v4");
let dexes = crate::query_dexs_list(&database).await.expect("list dexes must succeed"); let dexes = crate::query_dexs_list(&database).await.expect("list dexes must succeed");
assert_eq!(dexes.len(), 1); assert_eq!(dexes.len(), 1);
} }

View File

@@ -225,7 +225,7 @@ mod tests {
.expect("database init must succeed"); .expect("database init must succeed");
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
&database, &database,
&crate::DexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), &crate::DexDto::new("raydium_amm_v4".to_string(), "Raydium AMM v4".to_string(), None, None, true),
) )
.await .await
.expect("dex upsert must succeed"); .expect("dex upsert must succeed");

View File

@@ -181,7 +181,7 @@ mod tests {
.expect("database init must succeed"); .expect("database init must succeed");
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
&database, &database,
&crate::DexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), &crate::DexDto::new("raydium_amm_v4".to_string(), "Raydium AMM v4".to_string(), None, None, true),
) )
.await .await
.expect("dex upsert must succeed"); .expect("dex upsert must succeed");

View File

@@ -202,7 +202,7 @@ mod tests {
.expect("database init must succeed"); .expect("database init must succeed");
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
&database, &database,
&crate::DexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), &crate::DexDto::new("raydium_amm_v4".to_string(), "Raydium AMM v4".to_string(), None, None, true),
) )
.await .await
.expect("dex upsert must succeed"); .expect("dex upsert must succeed");

View File

@@ -140,7 +140,7 @@ mod tests {
.expect("database init must succeed"); .expect("database init must succeed");
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
&database, &database,
&crate::DexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), &crate::DexDto::new("raydium_amm_v4".to_string(), "Raydium AMM v4".to_string(), None, None, true),
) )
.await .await
.expect("dex upsert must succeed"); .expect("dex upsert must succeed");

View File

@@ -167,7 +167,7 @@ mod tests {
.expect("database init must succeed"); .expect("database init must succeed");
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
&database, &database,
&crate::DexDto::new("raydium".to_string(), "Raydium".to_string(), None, None, true), &crate::DexDto::new("raydium_amm_v4".to_string(), "Raydium AMM v4".to_string(), None, None, true),
) )
.await .await
.expect("dex upsert must succeed"); .expect("dex upsert must succeed");

View File

@@ -353,8 +353,8 @@ mod tests {
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
service.database().as_ref(), service.database().as_ref(),
&crate::DexDto::new( &crate::DexDto::new(
"raydium".to_string(), "raydium_amm_v4".to_string(),
"Raydium".to_string(), "Raydium AMM v4".to_string(),
Some("DexProgram111111111111111111111111111111111".to_string()), Some("DexProgram111111111111111111111111111111111".to_string()),
None, None,
true, true,

View File

@@ -1009,8 +1009,8 @@ mod tests {
let dex_id = crate::query_dexs_upsert( let dex_id = crate::query_dexs_upsert(
persistence.database().as_ref(), persistence.database().as_ref(),
&crate::DexDto::new( &crate::DexDto::new(
"raydium".to_string(), "raydium_amm_v4".to_string(),
"Raydium".to_string(), "Raydium AMM v4".to_string(),
Some("DexProgram111111111111111111111111111111111".to_string()), Some("DexProgram111111111111111111111111111111111".to_string()),
None, None,
true, true,

View File

@@ -92,7 +92,7 @@ mod tests {
#[test] #[test]
fn known_active_dexes_are_available_from_catalog() { fn known_active_dexes_are_available_from_catalog() {
let codes = [ let codes = [
"raydium", "raydium_amm_v4",
"raydium_cpmm", "raydium_cpmm",
"raydium_clmm", "raydium_clmm",
"pump_fun", "pump_fun",

View File

@@ -149,7 +149,7 @@ impl DexDetectService {
decoded_event: &crate::DexDecodedEventDto, decoded_event: &crate::DexDecodedEventDto,
) -> Result<crate::DexPoolDetectionResult, crate::Error> { ) -> Result<crate::DexPoolDetectionResult, crate::Error> {
let dex_id_result = let dex_id_result =
crate::dex_catalog::ensure_known_dex(self.database.as_ref(), "raydium").await; crate::dex_catalog::ensure_known_dex(self.database.as_ref(), "raydium_amm_v4").await;
let dex_id = match dex_id_result { let dex_id = match dex_id_result {
Ok(dex_id) => dex_id, Ok(dex_id) => dex_id,
Err(error) => return Err(error), Err(error) => return Err(error),

View File

@@ -19,8 +19,10 @@ pub struct DexSupportMatrixEntry {
pub family: &'static str, pub family: &'static str,
/// Protocol version or `unknown` when not verified locally. /// Protocol version or `unknown` when not verified locally.
pub version: &'static str, pub version: &'static str,
/// Surface type: `launch`, `bonding_curve`, `AMM`, `CLMM`, `DLMM`, `router`, `aggregator` or `unknown`. /// Technical surface type: `launch`, `bonding_curve`, `AMM`, `CLMM`, `DLMM`, `router`, `aggregator` or `unknown`.
pub surface_type: &'static str, pub surface_type: &'static str,
/// Strategic surface role used by the DEX-first roadmap: `dex_effective`, `aggregator_router`, `launch_surface` or `to_verify`.
pub surface_role: &'static str,
/// Primary Solana program id, when verified in local constants or docs. /// Primary Solana program id, when verified in local constants or docs.
pub program_id: std::option::Option<&'static str>, pub program_id: std::option::Option<&'static str>,
/// Optional router program id, when this entry uses a distinct router. /// Optional router program id, when this entry uses a distinct router.
@@ -63,8 +65,10 @@ pub struct DexSupportMatrixEntryDto {
pub family: std::string::String, pub family: std::string::String,
/// Protocol version or `unknown` when not verified locally. /// Protocol version or `unknown` when not verified locally.
pub version: std::string::String, pub version: std::string::String,
/// Surface type: `launch`, `bonding_curve`, `AMM`, `CLMM`, `DLMM`, `router`, `aggregator` or `unknown`. /// Technical surface type: `launch`, `bonding_curve`, `AMM`, `CLMM`, `DLMM`, `router`, `aggregator` or `unknown`.
pub surface_type: std::string::String, pub surface_type: std::string::String,
/// Strategic surface role used by the DEX-first roadmap: `dex_effective`, `aggregator_router`, `launch_surface` or `to_verify`.
pub surface_role: std::string::String,
/// Primary Solana program id, when verified in local constants or docs. /// Primary Solana program id, when verified in local constants or docs.
pub program_id: std::option::Option<std::string::String>, pub program_id: std::option::Option<std::string::String>,
/// Optional router program id, when this entry uses a distinct router. /// Optional router program id, when this entry uses a distinct router.
@@ -104,6 +108,7 @@ impl DexSupportMatrixEntryDto {
family: entry.family.to_string(), family: entry.family.to_string(),
version: entry.version.to_string(), version: entry.version.to_string(),
surface_type: entry.surface_type.to_string(), surface_type: entry.surface_type.to_string(),
surface_role: entry.surface_role.to_string(),
program_id: match entry.program_id { program_id: match entry.program_id {
Some(program_id) => Some(program_id.to_string()), Some(program_id) => Some(program_id.to_string()),
None => None, None => None,
@@ -138,6 +143,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "pump", family: "pump",
version: "bonding_curve", version: "bonding_curve",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: Some(crate::PUMP_FUN_PROGRAM_ID), program_id: Some(crate::PUMP_FUN_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -159,6 +165,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "pump", family: "pump",
version: "amm", version: "amm",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::PUMP_SWAP_PROGRAM_ID), program_id: Some(crate::PUMP_SWAP_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -180,6 +187,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "raydium", family: "raydium",
version: "cpmm", version: "cpmm",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::RAYDIUM_CPMM_PROGRAM_ID), program_id: Some(crate::RAYDIUM_CPMM_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -201,6 +209,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "raydium", family: "raydium",
version: "clmm", version: "clmm",
surface_type: "CLMM", surface_type: "CLMM",
surface_role: "dex_effective",
program_id: Some(crate::RAYDIUM_CLMM_PROGRAM_ID), program_id: Some(crate::RAYDIUM_CLMM_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -222,6 +231,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "raydium", family: "raydium",
version: "amm_v4", version: "amm_v4",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::RAYDIUM_AMM_V4_PROGRAM_ID), program_id: Some(crate::RAYDIUM_AMM_V4_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -237,33 +247,13 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
skip_reason: Some("not_observed_in_0_7_28_replay"), skip_reason: Some("not_observed_in_0_7_28_replay"),
catalog_enabled: true, catalog_enabled: true,
}, },
DexSupportMatrixEntry {
code: "raydium",
display_name: "Raydium AMM v4",
family: "raydium",
version: "amm_v4_alias",
surface_type: "AMM",
program_id: Some(crate::RAYDIUM_AMM_V4_PROGRAM_ID),
router_program_id: None,
program_id_status: "known",
observed: false,
decoded: true,
materialized: true,
trade_candidate: true,
candle_candidate: true,
pair_candidate: true,
pool_candidate: true,
status: "partial",
confidence: "medium",
skip_reason: Some("legacy_catalog_alias_for_raydium_amm_v4"),
catalog_enabled: true,
},
DexSupportMatrixEntry { DexSupportMatrixEntry {
code: "raydium_launchlab", code: "raydium_launchlab",
display_name: "Raydium LaunchLab", display_name: "Raydium LaunchLab",
family: "raydium", family: "raydium",
version: "launchlab", version: "launchlab",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID), program_id: Some(crate::RAYDIUM_LAUNCHLAB_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -285,6 +275,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "raydium", family: "raydium",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "to_verify", program_id_status: "to_verify",
@@ -306,6 +297,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "raydium", family: "raydium",
version: "router", version: "router",
surface_type: "router", surface_type: "router",
surface_role: "aggregator_router",
program_id: Some(crate::RAYDIUM_AMM_ROUTING_PROGRAM_ID), program_id: Some(crate::RAYDIUM_AMM_ROUTING_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -327,6 +319,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "raydium", family: "raydium",
version: "stable_swap", version: "stable_swap",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID), program_id: Some(crate::RAYDIUM_STABLE_SWAP_AMM_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -348,6 +341,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "meteora", family: "meteora",
version: "dlmm", version: "dlmm",
surface_type: "DLMM", surface_type: "DLMM",
surface_role: "dex_effective",
program_id: Some(crate::METEORA_DLMM_PROGRAM_ID), program_id: Some(crate::METEORA_DLMM_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -369,6 +363,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "meteora", family: "meteora",
version: "unknown", version: "unknown",
surface_type: "unknown", surface_type: "unknown",
surface_role: "to_verify",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "to_verify", program_id_status: "to_verify",
@@ -390,6 +385,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "meteora", family: "meteora",
version: "damm_v1", version: "damm_v1",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::METEORA_DAMM_V1_PROGRAM_ID), program_id: Some(crate::METEORA_DAMM_V1_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -411,6 +407,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "meteora", family: "meteora",
version: "damm_v2", version: "damm_v2",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::METEORA_DAMM_V2_PROGRAM_ID), program_id: Some(crate::METEORA_DAMM_V2_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -432,6 +429,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "meteora", family: "meteora",
version: "dbc", version: "dbc",
surface_type: "bonding_curve", surface_type: "bonding_curve",
surface_role: "dex_effective",
program_id: Some(crate::METEORA_DBC_PROGRAM_ID), program_id: Some(crate::METEORA_DBC_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -453,6 +451,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "orca", family: "orca",
version: "whirlpools", version: "whirlpools",
surface_type: "CLMM", surface_type: "CLMM",
surface_role: "dex_effective",
program_id: Some(crate::ORCA_WHIRLPOOLS_PROGRAM_ID), program_id: Some(crate::ORCA_WHIRLPOOLS_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -474,6 +473,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "fluxbeam", family: "fluxbeam",
version: "unknown", version: "unknown",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::FLUXBEAM_PROGRAM_ID), program_id: Some(crate::FLUXBEAM_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -495,6 +495,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "dexlab", family: "dexlab",
version: "unknown", version: "unknown",
surface_type: "AMM", surface_type: "AMM",
surface_role: "dex_effective",
program_id: Some(crate::DEXLAB_PROGRAM_ID), program_id: Some(crate::DEXLAB_PROGRAM_ID),
router_program_id: None, router_program_id: None,
program_id_status: "known", program_id_status: "known",
@@ -516,6 +517,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "bags", family: "bags",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -537,6 +539,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "bonk", family: "bonk",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -558,6 +561,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "bonk", family: "bonk",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -579,6 +583,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "bonk", family: "bonk",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -600,6 +605,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "okx", family: "okx",
version: "unknown", version: "unknown",
surface_type: "aggregator", surface_type: "aggregator",
surface_role: "aggregator_router",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -621,6 +627,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "boop", family: "boop",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -642,6 +649,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "moonshot", family: "moonshot",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -663,6 +671,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "believe", family: "believe",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -678,12 +687,57 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
skip_reason: Some("program_id_to_verify"), skip_reason: Some("program_id_to_verify"),
catalog_enabled: false, catalog_enabled: false,
}, },
DexSupportMatrixEntry {
code: "metadao",
display_name: "metaDAO",
family: "metadao",
version: "unknown",
surface_type: "unknown",
surface_role: "to_verify",
program_id: None,
router_program_id: None,
program_id_status: "to_verify",
observed: false,
decoded: false,
materialized: false,
trade_candidate: false,
candle_candidate: false,
pair_candidate: false,
pool_candidate: false,
status: "to_verify",
confidence: "low",
skip_reason: Some("surface_and_program_id_to_verify"),
catalog_enabled: false,
},
DexSupportMatrixEntry {
code: "printr",
display_name: "Printr",
family: "printr",
version: "unknown",
surface_type: "unknown",
surface_role: "to_verify",
program_id: None,
router_program_id: None,
program_id_status: "to_verify",
observed: false,
decoded: false,
materialized: false,
trade_candidate: false,
candle_candidate: false,
pair_candidate: false,
pool_candidate: false,
status: "to_verify",
confidence: "low",
skip_reason: Some("surface_and_program_id_to_verify"),
catalog_enabled: false,
},
DexSupportMatrixEntry { DexSupportMatrixEntry {
code: "zora", code: "zora",
display_name: "Zora", display_name: "Zora",
family: "zora", family: "zora",
version: "unknown", version: "unknown",
surface_type: "unknown", surface_type: "unknown",
surface_role: "to_verify",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "to_verify", program_id_status: "to_verify",
@@ -705,6 +759,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "moonit", family: "moonit",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -726,6 +781,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "launchbeam", family: "launchbeam",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -747,6 +803,7 @@ const DEX_SUPPORT_MATRIX_ENTRIES: &[DexSupportMatrixEntry] = &[
family: "heaven", family: "heaven",
version: "unknown", version: "unknown",
surface_type: "launch", surface_type: "launch",
surface_role: "launch_surface",
program_id: None, program_id: None,
router_program_id: None, router_program_id: None,
program_id_status: "unknown", program_id_status: "unknown",
@@ -812,7 +869,7 @@ pub fn dex_support_matrix_entry_by_program_id(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]
fn matrix_contains_required_0_7_29_entries() { fn matrix_contains_required_0_7_39_dex_first_entries() {
let codes = [ let codes = [
"pump_fun", "pump_fun",
"pump_swap", "pump_swap",
@@ -837,6 +894,8 @@ mod tests {
"launchbeam", "launchbeam",
"heaven", "heaven",
"dexlab", "dexlab",
"metadao",
"printr",
]; ];
for code in codes { for code in codes {
let entry = crate::dex_support_matrix_entry_by_code(code); let entry = crate::dex_support_matrix_entry_by_code(code);
@@ -860,6 +919,8 @@ mod tests {
"moonit", "moonit",
"launchbeam", "launchbeam",
"heaven", "heaven",
"metadao",
"printr",
]; ];
for code in codes { for code in codes {
let entry = match crate::dex_support_matrix_entry_by_code(code) { let entry = match crate::dex_support_matrix_entry_by_code(code) {
@@ -932,7 +993,7 @@ mod tests {
} }
#[test] #[test]
fn matrix_keeps_0_7_39_launch_surfaces_non_trade_materialized() { fn matrix_keeps_0_7_39_deferred_surfaces_non_trade_materialized() {
let codes = [ let codes = [
"raydium_launchlab", "raydium_launchlab",
"raydium_launchpad", "raydium_launchpad",
@@ -958,6 +1019,50 @@ mod tests {
} }
} }
#[test]
fn matrix_marks_effective_dexes_for_dex_first_work() {
let codes = [
"pump_swap",
"raydium_cpmm",
"raydium_clmm",
"raydium_amm_v4",
"raydium_stable_swap",
"meteora_dlmm",
"meteora_damm_v1",
"meteora_damm_v2",
"meteora_dbc",
"orca_whirlpools",
"fluxbeam",
"dexlab",
];
for code in codes {
let entry = match crate::dex_support_matrix_entry_by_code(code) {
Some(entry) => entry,
None => panic!("missing matrix entry for {}", code),
};
assert_eq!(entry.surface_role, "dex_effective", "{} must be DEX-first", code);
}
}
#[test]
fn matrix_keeps_metadao_and_printr_unverified_without_program_id() {
let codes = ["metadao", "printr"];
for code in codes {
let entry = match crate::dex_support_matrix_entry_by_code(code) {
Some(entry) => entry,
None => panic!("missing matrix entry for {}", code),
};
assert_eq!(entry.surface_role, "to_verify");
assert_eq!(entry.program_id_status, "to_verify");
assert!(entry.program_id.is_none());
assert!(!entry.decoded);
assert!(!entry.materialized);
assert!(!entry.trade_candidate);
assert!(!entry.candle_candidate);
assert!(!entry.catalog_enabled);
}
}
#[test] #[test]
fn matrix_dto_preserves_core_fields() { fn matrix_dto_preserves_core_fields() {
let entry = match crate::dex_support_matrix_entry_by_code("pump_swap") { let entry = match crate::dex_support_matrix_entry_by_code("pump_swap") {
@@ -967,6 +1072,7 @@ mod tests {
let dto = crate::DexSupportMatrixEntryDto::from_entry(entry); let dto = crate::DexSupportMatrixEntryDto::from_entry(entry);
assert_eq!(dto.code, "pump_swap"); assert_eq!(dto.code, "pump_swap");
assert_eq!(dto.program_id, Some(crate::PUMP_SWAP_PROGRAM_ID.to_string())); assert_eq!(dto.program_id, Some(crate::PUMP_SWAP_PROGRAM_ID.to_string()));
assert_eq!(dto.surface_role, "dex_effective");
assert!(dto.trade_candidate); assert!(dto.trade_candidate);
assert!(dto.candle_candidate); assert!(dto.candle_candidate);
} }

View File

@@ -104,7 +104,7 @@ impl LaunchOriginService {
return Self { database, persistence }; return Self { database, persistence };
} }
/// Ensures that every built-in launch surface tracked by `0.7.39` exists. /// Ensures that every deferred built-in launch surface exists.
pub async fn ensure_target_launch_surfaces(&self) -> Result<std::vec::Vec<i64>, crate::Error> { pub async fn ensure_target_launch_surfaces(&self) -> Result<std::vec::Vec<i64>, crate::Error> {
let mut surface_ids = std::vec::Vec::new(); let mut surface_ids = std::vec::Vec::new();
for spec in BUILTIN_LAUNCH_SURFACE_SPECS { for spec in BUILTIN_LAUNCH_SURFACE_SPECS {

View File

@@ -278,18 +278,26 @@ impl LocalPipelineValidationConfig {
return config; return config;
} }
/// Builds the `0.7.39` launch surface origin baseline validation config. /// Builds the `0.7.39` DEX-first effective swap surfaces validation config.
/// ///
/// This profile keeps the `0.7.38` metadata-gap semantics and requires the /// This profile keeps the `0.7.38` metadata-gap semantics and requires the
/// static DEX matrix invariants that prevent planned launch surfaces from /// static DEX matrix invariants that distinguish effective swap surfaces,
/// being treated as priced trade/candle producers before corpus-backed /// routers/aggregators, deferred launch surfaces and unverified candidates.
/// decoders are available. pub fn v0_7_39_dex_first_effective_swap_surfaces() -> Self {
pub fn v0_7_39_launch_surface_origin_baseline() -> Self {
let mut config = Self::v0_7_38_token_metadata_gap_prioritization(); let mut config = Self::v0_7_38_token_metadata_gap_prioritization();
config.profile_code = "0.7.39_launch_surface_origin_baseline".to_string(); config.profile_code = "0.7.39_dex_first_effective_swap_surfaces".to_string();
config.require_dex_support_matrix_semantics = true; config.require_dex_support_matrix_semantics = true;
return config; return config;
} }
/// Builds the legacy `0.7.39` launch-surface validation alias.
///
/// The implementation now delegates to the DEX-first profile so callers that
/// still pass the previous profile code do not accidentally revive the old
/// launch-surface priority.
pub fn v0_7_39_launch_surface_origin_baseline() -> Self {
return Self::v0_7_39_dex_first_effective_swap_surfaces();
}
} }
/// A single local pipeline validation issue. /// A single local pipeline validation issue.
@@ -519,11 +527,11 @@ impl LocalPipelineValidationService {
return self.validate_current_database(&config).await; return self.validate_current_database(&config).await;
} }
/// Diagnoses the current database with the `0.7.39` launch-origin baseline profile. /// Diagnoses the current database with the `0.7.39` DEX-first profile.
pub async fn validate_v0_7_39_current_database( pub async fn validate_v0_7_39_current_database(
&self, &self,
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> { ) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
let config = crate::LocalPipelineValidationConfig::v0_7_39_launch_surface_origin_baseline(); let config = crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
return self.validate_current_database(&config).await; return self.validate_current_database(&config).await;
} }
} }
@@ -649,6 +657,7 @@ pub fn validate_local_pipeline_diagnostics_summary(
|| config.profile_code == "0.7.36_meteora_family_consolidation" || config.profile_code == "0.7.36_meteora_family_consolidation"
|| config.profile_code == "0.7.37_token_metadata_catalog_enrichment" || config.profile_code == "0.7.37_token_metadata_catalog_enrichment"
|| config.profile_code == "0.7.38_token_metadata_gap_prioritization" || config.profile_code == "0.7.38_token_metadata_gap_prioritization"
|| config.profile_code == "0.7.39_dex_first_effective_swap_surfaces"
|| config.profile_code == "0.7.39_launch_surface_origin_baseline"; || config.profile_code == "0.7.39_launch_surface_origin_baseline";
if config.require_all_expected_dexes || missing_expected_dex_is_warning { if config.require_all_expected_dexes || missing_expected_dex_is_warning {
for expected_dex_code in &expected_dex_codes { for expected_dex_code in &expected_dex_codes {
@@ -898,16 +907,48 @@ fn validate_dex_support_matrix_semantics(
}); });
} }
if (entry.status == "planned" || entry.status == "to_verify" || entry.status == "unknown") if (entry.status == "planned" || entry.status == "to_verify" || entry.status == "unknown")
&& entry.surface_type == "launch" && (entry.surface_role == "launch_surface" || entry.surface_role == "to_verify")
&& (entry.decoded && (entry.decoded
|| entry.materialized || entry.materialized
|| entry.trade_candidate || entry.trade_candidate
|| entry.candle_candidate) || entry.candle_candidate)
{ {
issues.push(crate::LocalPipelineValidationIssueDto { issues.push(crate::LocalPipelineValidationIssueDto {
code: "inactive_launch_surface_matrix_entry_actionable".to_string(), code: "inactive_deferred_surface_matrix_entry_actionable".to_string(),
message: format!( message: format!(
"inactive launch surface '{}' must not be decoded, materialized, or priced as trade/candle candidate", "inactive deferred surface '{}' must not be decoded, materialized, or priced as trade/candle candidate",
entry_code
),
subject: Some(entry_code.clone()),
blocking: true,
});
}
if entry.surface_role == "aggregator_router"
&& (entry.trade_candidate || entry.candle_candidate || entry.catalog_enabled)
{
issues.push(crate::LocalPipelineValidationIssueDto {
code: "aggregator_router_matrix_entry_direct_trade_enabled".to_string(),
message: format!(
"aggregator/router '{}' must not be enabled as a direct trade/candle surface before proof",
entry_code
),
subject: Some(entry_code.clone()),
blocking: true,
});
}
if entry.surface_role == "to_verify"
&& (entry.program_id.is_some()
|| entry.program_id_status != "to_verify"
|| entry.catalog_enabled
|| entry.decoded
|| entry.materialized
|| entry.trade_candidate
|| entry.candle_candidate)
{
issues.push(crate::LocalPipelineValidationIssueDto {
code: "to_verify_matrix_entry_promoted_without_proof".to_string(),
message: format!(
"to-verify surface '{}' must not expose program id, catalog activation, decoding or trade/candle materialization without corpus proof",
entry_code entry_code
), ),
subject: Some(entry_code.clone()), subject: Some(entry_code.clone()),
@@ -1397,12 +1438,12 @@ mod tests {
} }
#[test] #[test]
fn validation_accepts_0_7_39_launch_surface_origin_baseline() { fn validation_accepts_0_7_39_dex_first_effective_swap_surfaces() {
let summary = make_0_7_28_summary_with_meteora(); let summary = make_0_7_28_summary_with_meteora();
let config = crate::LocalPipelineValidationConfig::v0_7_39_launch_surface_origin_baseline(); let config = crate::LocalPipelineValidationConfig::v0_7_39_dex_first_effective_swap_surfaces();
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config); let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
assert!(report.validation_passed); assert!(report.validation_passed);
assert_eq!(report.validation_profile_code, "0.7.39_launch_surface_origin_baseline"); assert_eq!(report.validation_profile_code, "0.7.39_dex_first_effective_swap_surfaces");
assert_eq!(report.blocking_issue_count, 0); assert_eq!(report.blocking_issue_count, 0);
} }