v0.4.8-pre.006

This commit is contained in:
2026-08-05 20:30:16 +02:00
parent 4187643148
commit 80c439c988
16 changed files with 997 additions and 131 deletions

View File

@@ -1,8 +1,21 @@
<!-- file: kb-lib/CHANGELOG.md -->
<!-- version: 21 -->
<!-- version: 23 -->
# CHANGELOG — kb-lib
## 0.4.8-pre.006 — matérialisation Solana Program Metadata
- active `MtMetadataMaterializer` comme matérialiseur contextualisé de la surface exacte `metadata.solana_program_metadata` ;
- matérialise les neuf instructions stables comme faits de mutation committés, sans leur attribuer lautorité de létat final ;
- matérialise les snapshots `Buffer` et `Metadata` comme états autoritatifs bornés, avec conservation intégrale des données directes et Buffer en base64 et SHA-256 ;
- conserve les URL et références `External` comme données on-chain sans fetch distant ni lecture implicite du compte référencé ;
- refuse les instructions échouées ou non committées et ignore les programmes, familles ou entrées étrangers ;
- ferme une matrice de onze projections : deux états de comptes et neuf faits dinstructions ;
- confirme que les neuf instructions stables sont courantes, non dépréciées et non remplacées ; lancien nom pré-stable du tag `5` reste une provenance de `Trim` seulement ;
- ajoute les helpers publics de matérialisation détats et le test dAPI externe correspondant.
- corrige le helper de test de snapshot afin dutiliser les variantes wire existantes `Encoding::Utf8` et `Format::Json`.
- précise que les opérations destructrices, irréversibles ou écrasantes restent exécutables : leur progression vers simulation, signature et envoi doit être gouvernée par le cadre commun `ExSafetyChecker`, et non supprimée du périmètre de lexécuteur.
## 0.4.8-pre.005 — instructions Solana Program Metadata
- active `DcMetadataSolanaProgramMetadataDecoder` pour les neuf discriminants stables `0..8` ;
@@ -14,6 +27,7 @@
- retire le décodeur Solana Program Metadata de linventaire des décodeurs réservés.
- aligne la structure du composant sur les règles du workspace : façade limitée aux sous-modules et réexports, implémentation déplacée dans `decoder.rs`, constantes centralisées dans `constants.rs` et accès internes via `crate::`.
- corrige les vecteurs négatifs `Initialize` afin de placer explicitement les valeurs invalides après les 16 octets du seed et de vérifier séparément `Encoding`, `Compression`, `Format` et `DataSource`.
- validation reçue le 5 août 2026 : `cargo fmt`, `cargo check --workspace`, `cargo clippy --all-targets`, audit workspace et 660 tests unitaires `kb-lib` réussis, ainsi que les tests dAPI externes et la matrice de nomenclature.
## 0.4.8-pre.004 — comptes Solana Program Metadata

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/README.md -->
<!-- version: 22 -->
<!-- version: 23 -->
# kb-lib
@@ -7,7 +7,7 @@
## Périmètre
La crate couvre actuellement Solana Core, SPL Memo, SPL Token classique, SPL Associated Token Account, Token-2022, le registre SPL ElGamal et Metaplex Token Metadata. Elle expose également les modèles wire bornés, les décodeurs de comptes `Buffer` et `Metadata` et le décodeur contextualisé des neuf instructions stables de Solana Program Metadata.
La crate couvre actuellement Solana Core, SPL Memo, SPL Token classique, SPL Associated Token Account, Token-2022, le registre SPL ElGamal et Metaplex Token Metadata. Elle expose également les modèles wire bornés, les décodeurs de comptes `Buffer` et `Metadata`, le décodeur contextualisé des neuf instructions stables et la matérialisation exhaustive de Solana Program Metadata.
Pour Solana Program Metadata, la surface publique fondatrice comprend :
@@ -21,6 +21,9 @@ Pour Solana Program Metadata, la surface publique fondatrice comprend :
- les neuf instructions stables `Write`, `Initialize`, `SetAuthority`, `SetData`, `SetImmutable`, `Trim`, `Close`, `Allocate` et `Extend` ;
- les formes runtime actuelles non produites par le SDK, notamment `SetData` sans remplacement de données et les suffixes ignorés de `SetImmutable`, `Trim` et `Close` ;
- une frontière historique où lancien nom pré-stable `WithdrawExcessLamports` du tag `5` reste une provenance de `Trim`, sans dixième entrée de couverture.
- deux projections détat autoritatives pour `Buffer` et `Metadata`, avec conservation bornée du contenu on-chain ;
- neuf faits de mutation dinstructions committées, non autoritatifs vis-à-vis de létat final et réconciliables avec les snapshots post-exécution ;
- une classification où les neuf instructions stables sont courantes, sans opération officiellement remplacée ou obsolète à annoter `Deprecated`.
Pour Metaplex Token Metadata, elle fournit :
@@ -53,7 +56,7 @@ Pour Metaplex Token Metadata, elle fournit :
- contrats `MtApi*` et matérialisateurs concrets ;
- contrats `ExApi*`, politiques de sécurité et exécuteurs `Ex*Executor` ;
- `ExMetadataMetaplexTokenMetadataExecutor`, `ExMetaplexTokenMetadataExecutionIntent` et `ExMetaplexTokenMetadataOperation` ;
- `DcMetadataSolanaProgramMetadataDecoder`, modèles `DcMetadataSpm*`, constantes `DC_METADATA_SPM_*` et fonctions `decoder_metadata_solana_program_metadata_decode_*_account` pour le contrat Solana Program Metadata ;
- `DcMetadataSolanaProgramMetadataDecoder`, modèles `DcMetadataSpm*`, constantes `DC_METADATA_SPM_*`, fonctions `decoder_metadata_solana_program_metadata_decode_*_account` et helpers `materializer_metadata_materialize_solana_program_metadata_*_snapshot` ;
- modèles canoniques `Md*` réexportés par la façade.
Les exemples dappel et invariants sont documentés dans [USAGE.md](USAGE.md).
@@ -68,7 +71,7 @@ Les exemples dappel et invariants sont documentés dans [USAGE.md](USAGE.md).
La surface fonctionnelle Metaplex de la crate est achevée. Les campagnes Devnet restantes relèvent de `kb-pipeline-demo-scenarios` et de `kb-app-demo-desktop`, non dun manque de builder dans `kb-lib`.
Pour Solana Program Metadata, les modèles wire, les décodeurs bornés de comptes et le décodeur contextualisé des neuf instructions stables sont actifs. `Buffer` accepte tout reliquat comme données allouées sans inventer de PDA stable après changement dautorité ; `Metadata` valide la dérivation canonical ou non-canonical et distingue le contenu logique de la capacité ajoutée par `Extend`. Les variantes qui dépendent de létat du compte restent des intentions wire jusquaux lectures stateful prévues, et aucune forme pré-stable nest déclarée compatible réseau sans preuve de cluster.
Pour Solana Program Metadata, les modèles wire, les décodeurs bornés de comptes, le décodeur contextualisé et la matérialisation des deux comptes et des neuf instructions stables sont actifs. `Buffer` accepte tout reliquat comme données allouées sans inventer de PDA stable après changement dautorité ; `Metadata` valide la dérivation canonical ou non-canonical et distingue le contenu logique de la capacité ajoutée par `Extend`. Les instructions produisent des faits committés non autoritatifs ; les snapshots post-exécution restent la source de létat final. Les variantes qui dépendent de létat du compte restent des intentions wire jusquaux lectures stateful prévues, et aucune forme pré-stable nest déclarée compatible réseau sans preuve de cluster.
Le registre ElGamal nest pas déclaré validé réellement sur réseau.
@@ -80,4 +83,5 @@ Le registre ElGamal nest pas déclaré validé réellement sur réseau.
- [Matrice contractuelle Metaplex](../test-fixtures/contract-matrices/METAPLEX_TOKEN_METADATA_MATRIX.json)
- [Matrice des comptes Solana Program Metadata](../test-fixtures/contract-matrices/SOLANA_PROGRAM_METADATA_ACCOUNT_MATRIX.json)
- [Matrice des instructions Solana Program Metadata](../test-fixtures/contract-matrices/SOLANA_PROGRAM_METADATA_INSTRUCTION_MATRIX.json)
- [Matrice de matérialisation Solana Program Metadata](../test-fixtures/contract-matrices/SOLANA_PROGRAM_METADATA_MATERIALIZATION_MATRIX.json)
- [Audit de linventaire et de lhistorique des instructions](../docs/audits/V0_4_8_PRE_005_SOLANA_PROGRAM_METADATA_INSTRUCTION_HISTORY_AUDIT.md)

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/USAGE.md -->
<!-- version: 11 -->
<!-- version: 12 -->
# Utilisation de kb-lib
@@ -153,6 +153,35 @@ println!("status={:?}", result.status);
Le tag `5` est toujours publié comme `trim`. Son ancien nom pré-stable `withdraw_excess_lamports` est conservé uniquement comme provenance, car aucune release stable ne lexpose comme instruction distincte. Les URL et références externes restent des données on-chain ; le décodeur ne réalise aucun fetch.
Le matérialiseur `MtMetadataMaterializer` accepte les neuf observations dinstructions de la surface exacte `metadata.solana_program_metadata`. Il refuse les transactions échouées et produit un fait de mutation par instruction. Ces faits ne remplacent pas un snapshot de compte : létat final doit être matérialisé depuis la lecture post-exécution.
```rust
let materializer = kb_lib::MtMetadataMaterializer;
if kb_lib::MtApiEventMaterializer::accepts_observation(&materializer, &observation) {
let result = kb_lib::MtApiEventMaterializer::materialize(&materializer, &observation);
println!("materialization status={:?}", result.status);
}
```
Les trois helpers détat acceptent les snapshots déjà validés par le décodeur :
- `materializer_metadata_materialize_solana_program_metadata_account_snapshot` distribue `Buffer` ou `Metadata` ;
- `materializer_metadata_materialize_solana_program_metadata_buffer_snapshot` conserve tous les octets du Buffer sous une forme bornée avec base64 et SHA-256 ;
- `materializer_metadata_materialize_solana_program_metadata_metadata_snapshot` conserve le contenu direct, lURL ou la référence externe, ainsi que lautorité, la mutabilité, le format et la capacité allouée.
```rust
let output = match kb_lib::materializer_metadata_materialize_solana_program_metadata_account_snapshot(
slot,
&snapshot,
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
println!("projection={}", output.payload_json);
```
Une URL reste une chaîne observée avec `fetched = false`. Une référence externe reste une adresse, un offset et une longueur avec `accountRead = false`. La matérialisation canonique ne réalise aucun enrichissement off-chain.
## Comptes Metaplex Token Metadata
Les fonctions `decoder_metadata_metaplex_token_metadata_decode_*_account` décodent les familles de comptes publiques prises en charge. Le consommateur doit fournir les données et le contexte attendus par la signature exacte de la fonction concernée. Les parseurs conservent les variantes historiques et refusent les longueurs, propriétaires ou suffixes incompatibles.

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/lib.rs
// version: 32
// version: 33
//! Consolidated decoder, executor, materializer and shared model library.
#![warn(missing_docs)]
@@ -1391,7 +1391,7 @@ pub use self::materializer::MtLifecycleMaterializer;
pub use self::materializer::MtLiquidityMaterializer;
/// Exposes the legacy common business materializer trait.
pub use self::materializer::MtMaterializer;
/// Token-2022 and Metaplex metadata snapshot materializer.
/// Token-2022, Metaplex and Solana Program Metadata materializer.
pub use self::materializer::MtMetadataMaterializer;
/// Reserved NFT materializer.
pub use self::materializer::MtNftMaterializer;
@@ -1439,6 +1439,12 @@ pub use self::materializer::materializer_fees_materialize_token_2022_state_snaps
pub use self::materializer::materializer_metadata_materialize_metaplex_account_snapshot;
/// Materializes one canonical Metaplex Metadata account snapshot.
pub use self::materializer::materializer_metadata_materialize_metaplex_metadata_snapshot;
/// Materializes one decoded Solana Program Metadata account snapshot.
pub use self::materializer::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
pub use self::materializer::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot;
/// Materializes one bounded Solana Program Metadata Metadata account snapshot.
pub use self::materializer::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
/// Materializes Token-2022 embedded metadata and group snapshots.
pub use self::materializer::materializer_metadata_materialize_token_2022_snapshot;
/// Materializes one bounded Token-2022 account state snapshot.
@@ -2048,6 +2054,12 @@ pub(crate) use self::executor::executor_spl_token_2022_build_prepared_plan;
pub(crate) use self::executor::executor_spl_token_build_prepared_plan;
/// Canonical processor name for the native and SPL administration materializer.
pub(crate) use self::materializer::MT_ADMIN_PROCESSOR_NAME;
/// Event families accepted by the Solana Program Metadata instruction materializer.
pub(crate) use self::materializer::MT_METADATA_SPM_ACCEPTED_FAMILIES;
/// Stable processor name for Solana Program Metadata projections.
pub(crate) use self::materializer::MT_METADATA_SPM_PROCESSOR_NAME;
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) use self::materializer::MT_METADATA_SPM_PROJECTION_VERSION;
/// Stable processor name for SPL Token and ATA risk facts.
pub(crate) use self::materializer::MT_RISK_PROCESSOR_NAME;
/// Stable projection contract version for SPL Token and ATA risk facts.
@@ -2068,6 +2080,8 @@ pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_ADMIN;
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_COMPLIANCE_AUDIT;
/// Canonical tracing target for the native lifecycle materializer.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_LIFECYCLE;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
/// Canonical tracing target for SPL Token and ATA risk facts.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_RISK;
/// Canonical tracing target for the native stake and vote materializer.

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/materializer.rs
// version: 8
// version: 9
//! Consolidated materializer modules.
@@ -73,12 +73,18 @@ pub use self::lending::MtLendingMaterializer;
pub use self::lifecycle::MtLifecycleMaterializer;
/// Reserved liquidity materializer.
pub use self::liquidity::MtLiquidityMaterializer;
/// Token-2022 and Metaplex metadata snapshot materializer.
/// Token-2022, Metaplex and Solana Program Metadata materializer.
pub use self::metadata::MtMetadataMaterializer;
/// Materializes one canonical non-Metadata Metaplex account snapshot.
pub use self::metadata::materializer_metadata_materialize_metaplex_account_snapshot;
/// Materializes one canonical Metaplex Metadata account snapshot.
pub use self::metadata::materializer_metadata_materialize_metaplex_metadata_snapshot;
/// Materializes one decoded Solana Program Metadata account snapshot.
pub use self::metadata::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
pub use self::metadata::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot;
/// Materializes one bounded Solana Program Metadata Metadata account snapshot.
pub use self::metadata::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
/// Materializes Token-2022 embedded metadata and group snapshots.
pub use self::metadata::materializer_metadata_materialize_token_2022_snapshot;
/// Reserved NFT materializer.
@@ -120,6 +126,14 @@ pub(crate) use self::admin::TRACING_TARGET_MATERIALIZER_ADMIN;
pub(crate) use self::compliance::TRACING_TARGET_MATERIALIZER_COMPLIANCE_AUDIT;
/// Canonical tracing target for the native lifecycle materializer.
pub(crate) use self::lifecycle::TRACING_TARGET_MATERIALIZER_LIFECYCLE;
/// Event families accepted by the Solana Program Metadata instruction materializer.
pub(crate) use self::metadata::MT_METADATA_SPM_ACCEPTED_FAMILIES;
/// Stable processor name for Solana Program Metadata projections.
pub(crate) use self::metadata::MT_METADATA_SPM_PROCESSOR_NAME;
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) use self::metadata::MT_METADATA_SPM_PROJECTION_VERSION;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
/// Stable processor name for SPL Token and ATA risk facts.
pub(crate) use self::risk::MT_RISK_PROCESSOR_NAME;
/// Stable projection contract version for SPL Token and ATA risk facts.

View File

@@ -1,11 +1,12 @@
// file: kb-lib/src/materializer/metadata.rs
// version: 4
// version: 5
//! `metadata` materializer family.
mod core;
mod solana_program_metadata;
/// Token-2022 and Metaplex metadata snapshot materializer.
/// Token-2022, Metaplex and Solana Program Metadata materializer.
pub use self::core::MtMetadataMaterializer;
/// Materializes one canonical non-Metadata Metaplex account snapshot.
pub use self::core::materializer_metadata_materialize_metaplex_account_snapshot;
@@ -13,3 +14,18 @@ pub use self::core::materializer_metadata_materialize_metaplex_account_snapshot;
pub use self::core::materializer_metadata_materialize_metaplex_metadata_snapshot;
/// Materializes Token-2022 embedded metadata and group snapshots.
pub use self::core::materializer_metadata_materialize_token_2022_snapshot;
/// Materializes one decoded Solana Program Metadata account snapshot.
pub use self::solana_program_metadata::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
pub use self::solana_program_metadata::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot;
/// Materializes one bounded Solana Program Metadata Metadata account snapshot.
pub use self::solana_program_metadata::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
/// Event families accepted by the Solana Program Metadata instruction materializer.
pub(crate) use self::solana_program_metadata::MT_METADATA_SPM_ACCEPTED_FAMILIES;
/// Stable processor name for Solana Program Metadata projections.
pub(crate) use self::solana_program_metadata::MT_METADATA_SPM_PROCESSOR_NAME;
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) use self::solana_program_metadata::MT_METADATA_SPM_PROJECTION_VERSION;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) use self::solana_program_metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;

View File

@@ -1,7 +1,7 @@
// file: kb-lib/src/materializer/metadata/core.rs
// version: 6
// version: 7
//! Stable Token-2022 and Metaplex metadata snapshot materializer.
//! Stable Token-2022, Metaplex and Solana Program Metadata materializer.
/// Initial materializer implementation placeholder.
#[derive(Clone, Debug, Default)]
@@ -16,8 +16,13 @@ impl crate::MtMaterializer for crate::MtMetadataMaterializer {
return env!("CARGO_PKG_VERSION");
}
fn accepts_event(&self, _event: &crate::MdDecodedProtocolEvent) -> bool {
return false;
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
return event.event_family == crate::MdEventFamily::Metadata
&& event.program_id.0 == kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID
&& event.surface_code.0 == crate::DC_METADATA_SPM_SURFACE_CODE
&& crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES
.iter()
.any(|(_, code)| return *code == event.event_name.0.as_str());
}
fn materialize_event(

View File

@@ -0,0 +1,24 @@
// file: kb-lib/src/materializer/metadata/solana_program_metadata.rs
// version: 1
//! Solana Program Metadata materialization surface.
mod constants;
mod instruction;
mod state;
/// Materializes one decoded Solana Program Metadata account snapshot.
pub use self::state::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
pub use self::state::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot;
/// Materializes one bounded Solana Program Metadata Metadata account snapshot.
pub use self::state::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
/// Event families accepted by the Solana Program Metadata instruction materializer.
pub(crate) use self::constants::MT_METADATA_SPM_ACCEPTED_FAMILIES;
/// Stable processor name for Solana Program Metadata projections.
pub(crate) use self::constants::MT_METADATA_SPM_PROCESSOR_NAME;
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) use self::constants::MT_METADATA_SPM_PROJECTION_VERSION;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) use self::constants::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;

View File

@@ -0,0 +1,16 @@
// file: kb-lib/src/materializer/metadata/solana_program_metadata/constants.rs
// version: 1
//! Solana Program Metadata materializer constants.
/// Event families accepted by the Solana Program Metadata instruction materializer.
pub(crate) const MT_METADATA_SPM_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
&[crate::MdEventFamily::Metadata];
/// Stable processor name for Solana Program Metadata projections.
pub(crate) const MT_METADATA_SPM_PROCESSOR_NAME: &str =
"kb-lib.materializer.metadata.solana_program_metadata";
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) const MT_METADATA_SPM_PROJECTION_VERSION: u16 = 1;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) const TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA: &str =
"kb-lib.materializer.metadata.solana_program_metadata";

View File

@@ -0,0 +1,325 @@
// file: kb-lib/src/materializer/metadata/solana_program_metadata/instruction.rs
// version: 1
//! Committed Solana Program Metadata instruction projections.
impl crate::MtApiEventMaterializer for crate::MtMetadataMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: crate::MT_METADATA_SPM_PROCESSOR_NAME.to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return crate::MT_METADATA_SPM_ACCEPTED_FAMILIES;
}
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
return observation.event.event_family == crate::MdEventFamily::Metadata
&& observation.event.program_id.0
== kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID
&& observation.event.surface_code.0 == crate::DC_METADATA_SPM_SURFACE_CODE
&& payload_contract_matches(observation)
&& crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES
.iter()
.any(|(_, code)| return *code == observation.event.event_name.0.as_str());
}
fn transaction_policy(
&self,
_family: crate::MdEventFamily,
) -> crate::MtApiMaterializationTransactionPolicy {
return crate::MtApiMaterializationTransactionPolicy::SuccessfulCommittedOnly;
}
fn materialize(
&self,
observation: &crate::DcApiDecodedObservation,
) -> crate::MtApiMaterializerExecutionResult {
if !crate::MtApiEventMaterializer::accepts_observation(self, observation) {
return crate::MtApiMaterializerExecutionResult::ignored();
}
if observation.transaction_failed || !observation.observation_committed {
return crate::MtApiMaterializerExecutionResult::refused(
"failed_transaction_solana_program_metadata_refused",
"failed or uncommitted Solana Program Metadata instructions cannot create mutation outputs",
);
}
let operation = observation.event.event_name.0.as_str();
let projection = instruction_projection(operation, &observation.payload_json);
let output = crate::MtApiMaterializedOutput {
output_key: format!(
"solana_program_metadata_instruction:{}:{}:{}",
observation.event.signature.0, observation.event.instruction_path.0, operation
),
family: crate::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_METADATA_SPM_PROJECTION_VERSION,
"domain": "solana_program_metadata",
"projectionKind": "committed_instruction_mutation",
"projectionSemantics": "committed_instruction_fact_non_authoritative_state",
"operation": operation,
"programId": observation.event.program_id.0.clone(),
"signature": observation.event.signature.0.clone(),
"slot": observation.event.slot.0,
"instructionPath": observation.event.instruction_path.0.clone(),
"sourceKind": observation.event.source_kind,
"transactionSucceeded": true,
"stateProjectionAuthority": "post_execution_account_snapshot",
"authoritativeFinalStateCaptured": false,
"projection": projection,
"decodedPayload": observation.payload_json.clone(),
"externalContentFetched": false,
"externalAccountRead": false,
"provenance": {
"processorName": crate::MT_METADATA_SPM_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"decoderProof": observation.proof.clone()
}
}),
};
tracing::debug!(
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA,
action = "materialize_solana_program_metadata_instruction",
operation = operation,
signature = %observation.event.signature.0,
instruction_path = %observation.event.instruction_path.0,
output_count = 1_usize,
"materialize committed Solana Program Metadata instruction"
);
return crate::MtApiMaterializerExecutionResult {
status: crate::MtApiMaterializerOutcomeStatus::Inserted,
outputs: std::vec![output],
diagnostics: std::vec::Vec::new(),
};
}
}
fn payload_contract_matches(observation: &crate::DcApiDecodedObservation) -> bool {
let instruction =
observation.payload_json.get("instruction").and_then(serde_json::Value::as_str);
let program_id = observation.payload_json.get("programId").and_then(serde_json::Value::as_str);
return instruction == std::option::Option::Some(observation.event.event_name.0.as_str())
&& program_id
== std::option::Option::Some(
kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID,
);
}
fn instruction_projection(operation: &str, payload: &serde_json::Value) -> serde_json::Value {
let parameters = match payload.get("parameters") {
std::option::Option::Some(value) => value.clone(),
std::option::Option::None => serde_json::Value::Null,
};
let accounts = match payload.get("accounts") {
std::option::Option::Some(value) => value.clone(),
std::option::Option::None => serde_json::Value::Null,
};
return serde_json::json!({
"stateTransition": state_transition(operation),
"targetAccount": target_account(operation, &accounts),
"authority": account_for_role(&accounts, "authority"),
"destination": account_for_role(&accounts, "destination"),
"sourceBuffer": account_for_role(&accounts, "source_buffer"),
"buffer": account_for_role(&accounts, "buffer"),
"program": account_for_role(&accounts, "program"),
"programData": account_for_role(&accounts, "program_data"),
"parameters": parameters,
"accounts": accounts,
"currentStableInstruction": true,
"deprecated": false,
"replaced": false,
"executionPolicy": "current_candidate",
"preStableAlias": if operation == "trim" {
serde_json::Value::String("withdraw_excess_lamports".to_string())
} else {
serde_json::Value::Null
},
"preStableAliasDecodedSeparately": false
});
}
fn state_transition(operation: &str) -> &'static str {
match operation {
"write" => return "buffer_content_written",
"initialize" => return "metadata_account_initialized",
"set_authority" => return "account_authority_updated",
"set_data" => return "metadata_data_configuration_updated",
"set_immutable" => return "metadata_account_marked_immutable",
"trim" => return "account_capacity_trimmed",
"close" => return "account_closed",
"allocate" => return "buffer_account_allocated",
"extend" => return "account_capacity_extended",
_ => return "unknown",
}
}
fn target_account(operation: &str, accounts: &serde_json::Value) -> serde_json::Value {
let roles: &[&str] = match operation {
"write" | "allocate" => &["buffer"],
"initialize" | "set_data" | "set_immutable" => &["metadata"],
"set_authority" | "trim" | "close" | "extend" => &["account"],
_ => &[],
};
for role in roles {
let value = account_for_role(accounts, role);
if !value.is_null() {
return value;
}
}
return serde_json::Value::Null;
}
fn account_for_role(accounts: &serde_json::Value, role: &str) -> serde_json::Value {
let values = match accounts.as_array() {
std::option::Option::Some(value) => value,
std::option::Option::None => return serde_json::Value::Null,
};
for value in values {
let candidate = value.get("role").and_then(serde_json::Value::as_str);
let present = match value.get("present").and_then(serde_json::Value::as_bool) {
std::option::Option::Some(candidate) => candidate,
std::option::Option::None => true,
};
if candidate == std::option::Option::Some(role) && present {
return match value.get("accountKey") {
std::option::Option::Some(candidate) => candidate.clone(),
std::option::Option::None => serde_json::Value::Null,
};
}
}
return serde_json::Value::Null;
}
#[cfg(test)]
mod tests {
const MATRIX_JSON: &str = include_str!(
"../../../../../test-fixtures/contract-matrices/SOLANA_PROGRAM_METADATA_MATERIALIZATION_MATRIX.json"
);
fn observation(operation: &str, committed: bool) -> crate::DcApiDecodedObservation {
return crate::DcApiDecodedObservation {
event_key: format!("solana_program_metadata:{operation}:0"),
event: crate::MdDecodedProtocolEvent {
signature: crate::MdSignature("signature111".to_string()),
slot: crate::MdSlot(42),
instruction_path: crate::MdInstructionPath("0".to_string()),
program_id: crate::MdProgramId(
kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID.to_string(),
),
protocol_code: crate::MdProtocolCode(
crate::DC_METADATA_SPM_SURFACE_CODE.to_string(),
),
surface_code: crate::MdSurfaceCode(crate::DC_METADATA_SPM_SURFACE_CODE.to_string()),
event_code: crate::MdEventCode(format!(
"{}.{}",
crate::DC_METADATA_SPM_SURFACE_CODE,
operation
)),
event_name: crate::MdEventName(operation.to_string()),
event_family: crate::MdEventFamily::Metadata,
source_kind: crate::MdEventSourceKind::Instruction,
confidence: crate::MdDecoderConfidence::ManualExact,
},
payload_json: serde_json::json!({
"programId": kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID,
"instruction": operation,
"parameters": {"length": 8},
"accounts": [
{"role":"account","accountKey":"account111","present":true},
{"role":"authority","accountKey":"authority111","present":true}
],
"wire": {"sha256":"00"}
}),
transaction_failed: !committed,
transaction_error: if committed {
std::option::Option::None
} else {
std::option::Option::Some(serde_json::json!({"InstructionError":[0,"Custom"]}))
},
observation_committed: committed,
proof: crate::DcApiDecoderProof {
kind: crate::DcApiDecoderProofKind::Manual,
confidence: crate::MdDecoderConfidence::ManualExact,
evidence: std::vec!["wire".to_string()],
},
};
}
#[test]
fn every_stable_instruction_has_one_materialized_mutation_fact() {
let materializer = crate::MtMetadataMaterializer;
for (_, operation) in crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES.iter().copied() {
let value = observation(operation, true);
assert!(crate::MtApiEventMaterializer::accepts_observation(&materializer, &value));
let result = crate::MtApiEventMaterializer::materialize(&materializer, &value);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::Inserted);
assert_eq!(result.outputs.len(), 1);
assert_eq!(result.outputs[0].payload_json["operation"], *operation);
assert_eq!(result.outputs[0].payload_json["projection"]["deprecated"], false);
assert_eq!(result.outputs[0].payload_json["projection"]["replaced"], false);
}
}
#[test]
fn failed_instruction_is_refused_and_foreign_surface_is_ignored() {
let materializer = crate::MtMetadataMaterializer;
let failed = observation("set_data", false);
let failure = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
assert_eq!(failure.status, crate::MtApiMaterializerOutcomeStatus::Refused);
let mut foreign = observation("set_data", true);
foreign.event.program_id =
crate::MdProgramId(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID.to_string());
let ignored = crate::MtApiEventMaterializer::materialize(&materializer, &foreign);
assert_eq!(ignored.status, crate::MtApiMaterializerOutcomeStatus::Ignored);
}
#[test]
fn materialization_matrix_matches_two_account_states_and_nine_instructions() {
let parsed = serde_json::from_str::<serde_json::Value>(MATRIX_JSON);
assert!(parsed.is_ok());
let matrix = match parsed {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let accounts = match matrix.get("accountSnapshots").and_then(serde_json::Value::as_array) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let instructions =
match matrix.get("instructionFacts").and_then(serde_json::Value::as_array) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
assert_eq!(accounts.len(), 2);
assert_eq!(instructions.len(), crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES.len());
for (position, (tag, operation)) in
crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES.iter().copied().enumerate()
{
assert_eq!(instructions[position]["tag"], tag);
assert_eq!(instructions[position]["entryCode"], operation);
assert_eq!(instructions[position]["deprecated"], false);
assert_eq!(instructions[position]["replaced"], false);
assert_eq!(
instructions[position]["stateTransition"],
super::state_transition(operation)
);
}
}
#[test]
fn trim_keeps_prestable_alias_as_provenance_only() {
let materializer = crate::MtMetadataMaterializer;
let value = observation("trim", true);
let result = crate::MtApiEventMaterializer::materialize(&materializer, &value);
assert_eq!(
result.outputs[0].payload_json["projection"]["preStableAlias"],
"withdraw_excess_lamports"
);
assert_eq!(
result.outputs[0].payload_json["projection"]["preStableAliasDecodedSeparately"],
false
);
}
}

View File

@@ -0,0 +1,343 @@
// file: kb-lib/src/materializer/metadata/solana_program_metadata/state.rs
// version: 2
//! Authoritative Solana Program Metadata account-state projections.
use base64::Engine; // rust-rules: trait-import
use sha2::Digest; // rust-rules: trait-import
/// Materializes one decoded Solana Program Metadata account snapshot.
pub fn materializer_metadata_materialize_solana_program_metadata_account_snapshot(
slot: u64,
snapshot: &crate::DcMetadataSpmAccountSnapshot,
) -> std::result::Result<crate::MtApiMaterializedOutput, String> {
match snapshot {
crate::DcMetadataSpmAccountSnapshot::Buffer(value) => {
return crate::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot(
slot,
value,
);
},
crate::DcMetadataSpmAccountSnapshot::Metadata(value) => {
return crate::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot(
slot,
value,
);
},
}
}
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
pub fn materializer_metadata_materialize_solana_program_metadata_buffer_snapshot(
slot: u64,
snapshot: &crate::DcMetadataSpmBufferAccountSnapshot,
) -> std::result::Result<crate::MtApiMaterializedOutput, String> {
if snapshot.account.trim().is_empty() {
return std::result::Result::Err(
"Solana Program Metadata Buffer materialization requires a non-empty account"
.to_string(),
);
}
if snapshot.program.as_ref().is_some_and(|value| return value.trim().is_empty())
|| snapshot.authority.as_ref().is_some_and(|value| return value.trim().is_empty())
{
return std::result::Result::Err(
"Solana Program Metadata Buffer optional identities must not be empty".to_string(),
);
}
if snapshot.data.len() != snapshot.allocated_data_bytes {
return std::result::Result::Err(
"Solana Program Metadata Buffer allocated byte count does not match decoded data"
.to_string(),
);
}
if snapshot.allocated_data_bytes
> crate::DC_METADATA_SPM_MAX_ACCOUNT_BYTES
.saturating_sub(crate::DC_METADATA_SPM_BUFFER_HEADER_BYTES)
{
return std::result::Result::Err(
"Solana Program Metadata Buffer exceeds the bounded account-data contract".to_string(),
);
}
let seed_hex = hex(snapshot.seed.as_bytes());
let data = bytes_projection(snapshot.data.as_slice());
return std::result::Result::Ok(crate::MtApiMaterializedOutput {
output_key: format!("solana_program_metadata_account_state:{}", snapshot.account),
family: crate::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_METADATA_SPM_PROJECTION_VERSION,
"domain": "solana_program_metadata",
"projectionKind": "buffer_state",
"projectionSemantics": "authoritative_bounded_owned_account_snapshot",
"account": snapshot.account,
"slot": slot,
"programId": kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID,
"accountDiscriminator": "buffer",
"metadataProgram": snapshot.program,
"authority": snapshot.authority,
"mutable": snapshot.authority.is_some(),
"canonical": snapshot.canonical,
"seedHex": seed_hex,
"allocatedDataBytes": snapshot.allocated_data_bytes,
"data": data,
"metadataSource": "solana_program_metadata_owned_buffer_account",
"externalContentFetched": false,
"externalAccountRead": false,
"instructionProjectionRole": "mutation_observation_only_no_duplicate_state",
"provenance": {
"processorName": crate::MT_METADATA_SPM_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"source": "bounded_solana_program_metadata_account_decoder"
}
}),
});
}
/// Materializes one bounded Solana Program Metadata Metadata account snapshot.
pub fn materializer_metadata_materialize_solana_program_metadata_metadata_snapshot(
slot: u64,
snapshot: &crate::DcMetadataSpmMetadataAccountSnapshot,
) -> std::result::Result<crate::MtApiMaterializedOutput, String> {
if snapshot.account.trim().is_empty() || snapshot.program.trim().is_empty() {
return std::result::Result::Err(
"Solana Program Metadata state materialization requires account and program identities"
.to_string(),
);
}
if snapshot.authority.as_ref().is_some_and(|value| return value.trim().is_empty()) {
return std::result::Result::Err(
"Solana Program Metadata authority must not be empty when present".to_string(),
);
}
if snapshot.data_source != snapshot.data.source() {
return std::result::Result::Err(
"Solana Program Metadata data source does not match decoded content".to_string(),
);
}
if let std::result::Result::Err(error) = snapshot.data.validate() {
return std::result::Result::Err(error.to_string());
}
let logical_data_bytes = match usize::try_from(snapshot.data_length) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
return std::result::Result::Err(
"Solana Program Metadata logical data length is not representable".to_string(),
);
},
};
if logical_data_bytes != snapshot.data.wire_byte_len() {
return std::result::Result::Err(
"Solana Program Metadata logical data length does not match decoded content"
.to_string(),
);
}
if snapshot.allocated_data_bytes
> crate::DC_METADATA_SPM_MAX_ACCOUNT_BYTES
.saturating_sub(crate::DC_METADATA_SPM_METADATA_HEADER_BYTES)
{
return std::result::Result::Err(
"Solana Program Metadata state exceeds the bounded account-data contract".to_string(),
);
}
if snapshot.allocated_data_bytes
!= logical_data_bytes.saturating_add(snapshot.trailing_capacity_bytes)
{
return std::result::Result::Err(
"Solana Program Metadata allocated capacity is inconsistent".to_string(),
);
}
let seed_hex = hex(snapshot.seed.as_bytes());
let data = data_projection(&snapshot.data);
return std::result::Result::Ok(crate::MtApiMaterializedOutput {
output_key: format!("solana_program_metadata_account_state:{}", snapshot.account),
family: crate::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_METADATA_SPM_PROJECTION_VERSION,
"domain": "solana_program_metadata",
"projectionKind": "metadata_state",
"projectionSemantics": "authoritative_bounded_owned_account_snapshot",
"account": snapshot.account,
"slot": slot,
"programId": kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID,
"accountDiscriminator": "metadata",
"bump": snapshot.bump,
"metadataProgram": snapshot.program,
"authority": snapshot.authority,
"mutable": snapshot.mutable,
"canonical": snapshot.canonical,
"seedHex": seed_hex,
"encoding": snapshot.encoding,
"compression": snapshot.compression,
"format": snapshot.format,
"dataSource": snapshot.data_source,
"dataLength": snapshot.data_length,
"allocatedDataBytes": snapshot.allocated_data_bytes,
"trailingCapacityBytes": snapshot.trailing_capacity_bytes,
"data": data,
"metadataSource": "solana_program_metadata_owned_metadata_account",
"externalContentFetched": false,
"externalAccountRead": false,
"instructionProjectionRole": "mutation_observation_only_no_duplicate_state",
"provenance": {
"processorName": crate::MT_METADATA_SPM_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"source": "bounded_solana_program_metadata_account_decoder"
}
}),
});
}
fn data_projection(data: &crate::DcMetadataSpmData) -> serde_json::Value {
match data {
crate::DcMetadataSpmData::Direct(value) => {
let mut projection = bytes_projection(value.as_slice());
projection["kind"] = serde_json::json!("direct");
return projection;
},
crate::DcMetadataSpmData::Url(value) => {
return serde_json::json!({
"kind": "url",
"value": value,
"lengthBytes": value.len(),
"sha256": hash(value.as_bytes()),
"fetched": false
});
},
crate::DcMetadataSpmData::External(value) => {
return serde_json::json!({
"kind": "external",
"address": value.address.to_string(),
"offset": value.offset,
"length": value.length.map(std::num::NonZeroU32::get),
"wireLengthBytes": crate::DC_METADATA_SPM_EXTERNAL_DATA_BYTES,
"accountRead": false
});
},
}
}
fn bytes_projection(bytes: &[u8]) -> serde_json::Value {
return serde_json::json!({
"lengthBytes": bytes.len(),
"sha256": hash(bytes),
"base64": base64::engine::general_purpose::STANDARD.encode(bytes)
});
}
fn hash(bytes: &[u8]) -> std::string::String {
let digest = sha2::Sha256::digest(bytes);
let mut output = std::string::String::with_capacity(64);
for byte in digest {
output.push_str(format!("{byte:02x}").as_str());
}
return output;
}
fn hex(bytes: &[u8]) -> std::string::String {
let mut output = std::string::String::with_capacity(bytes.len().saturating_mul(2));
for byte in bytes {
output.push_str(format!("{byte:02x}").as_str());
}
return output;
}
#[cfg(test)]
mod tests {
#[test]
fn buffer_snapshot_preserves_all_bounded_bytes_and_authority_state() {
let snapshot = crate::DcMetadataSpmBufferAccountSnapshot {
account: "buffer111".to_string(),
program: std::option::Option::Some("program111".to_string()),
authority: std::option::Option::Some("authority111".to_string()),
canonical: true,
seed: match crate::DcMetadataSpmSeed::from_wire_bytes(&[7_u8; 16]) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => crate::DcMetadataSpmSeed::default(),
},
data: std::vec![1, 2, 3],
allocated_data_bytes: 3,
};
let output =
crate::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot(
42, &snapshot,
);
assert!(output.is_ok());
let payload = match output.as_ref() {
std::result::Result::Ok(value) => value.payload_json.clone(),
std::result::Result::Err(_) => serde_json::Value::Null,
};
assert_eq!(payload["projectionKind"], "buffer_state");
assert_eq!(payload["data"]["base64"], "AQID");
assert_eq!(payload["mutable"], true);
}
#[test]
fn metadata_snapshots_materialize_every_onchain_source_without_resolution() {
let direct = metadata_snapshot(crate::DcMetadataSpmData::Direct(std::vec![4, 5]));
let direct_output =
crate::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot(
9, &direct,
);
assert_eq!(
direct_output
.as_ref()
.map(|value| return value.payload_json["data"]["kind"].clone()),
std::result::Result::Ok(serde_json::json!("direct"))
);
let url_value = "https://example.invalid/idl.json".to_string();
let mut url = metadata_snapshot(crate::DcMetadataSpmData::Url(url_value.clone()));
url.data_source = crate::DcMetadataSpmDataSource::Url;
url.data_length = match u32::try_from(url_value.len()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => 0,
};
url.allocated_data_bytes = url_value.len();
let url_output =
crate::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot(
10, &url,
);
assert_eq!(
url_output
.as_ref()
.map(|value| return value.payload_json["data"]["fetched"].clone()),
std::result::Result::Ok(serde_json::json!(false))
);
}
#[test]
fn inconsistent_snapshot_lengths_fail_closed() {
let mut snapshot = metadata_snapshot(crate::DcMetadataSpmData::Direct(std::vec![1, 2]));
snapshot.data_length = 1;
assert!(
crate::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot(
1, &snapshot
)
.is_err()
);
}
fn metadata_snapshot(
data: crate::DcMetadataSpmData,
) -> crate::DcMetadataSpmMetadataAccountSnapshot {
return crate::DcMetadataSpmMetadataAccountSnapshot {
account: "metadata111".to_string(),
bump: 2,
program: "program111".to_string(),
authority: std::option::Option::Some("authority111".to_string()),
mutable: true,
canonical: true,
seed: crate::DcMetadataSpmSeed::default(),
encoding: crate::DcMetadataSpmEncoding::Utf8,
compression: crate::DcMetadataSpmCompression::None,
format: crate::DcMetadataSpmFormat::Json,
data_source: crate::DcMetadataSpmDataSource::Direct,
data_length: match u32::try_from(data.wire_byte_len()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => 0,
},
allocated_data_bytes: data.wire_byte_len(),
trailing_capacity_bytes: 0,
data,
};
}
}

View File

@@ -1,5 +1,5 @@
// file: kb-lib/tests/external_materializer_api.rs
// version: 5
// version: 6
//! Downstream-style compilation contract for externally implemented materializers.
@@ -50,6 +50,7 @@ fn external_materializer_uses_only_the_public_kb_lib_contract() {
assert_event_materializer::<kb_lib::MtGovernanceMaterializer>();
assert_event_materializer::<kb_lib::MtLendingMaterializer>();
assert_event_materializer::<kb_lib::MtLifecycleMaterializer>();
assert_event_materializer::<kb_lib::MtMetadataMaterializer>();
assert_event_materializer::<kb_lib::MtLiquidityMaterializer>();
assert_event_materializer::<kb_lib::MtNftMaterializer>();
assert_event_materializer::<kb_lib::MtOracleMaterializer>();
@@ -83,6 +84,9 @@ fn external_materializer_uses_only_the_public_kb_lib_contract() {
let _ = kb_lib::materializer_admin_materialize_elgamal_registry_state_snapshot;
let _ = kb_lib::materializer_metadata_materialize_metaplex_account_snapshot;
let _ = kb_lib::materializer_metadata_materialize_metaplex_metadata_snapshot;
let _ = kb_lib::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
let _ = kb_lib::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot;
let _ = kb_lib::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
let _ = kb_lib::materializer_admin_materialize_token_2022_state_snapshots;
let _ = kb_lib::materializer_fees_materialize_token_2022_state_snapshots;
let _ = kb_lib::materializer_metadata_materialize_token_2022_snapshot;