v0.4.8-pre.008

This commit is contained in:
2026-08-06 06:12:54 +02:00
parent 44088c71c9
commit f576fbade2
52 changed files with 3592 additions and 420 deletions

View File

@@ -1,8 +1,19 @@
<!-- file: kb-lib/CHANGELOG.md -->
<!-- version: 28 -->
<!-- version: 30 -->
# CHANGELOG — kb-lib
## 0.4.8-pre.008 — matérialiseurs metadata spécialisés
- corrige le décodeur Solana Program Metadata pour interpréter les flags `signer` et `writable` du replay comme des privilèges globaux de message : les privilèges requis sont désormais des minima, et les sur-ensembles légitimes dus au fee payer ou à dautres instructions ne sont plus rejetés ;
- ajoute une régression couvrant les neuf instructions avec une autorité signer et writable au niveau du message, tout en conservant le refus des privilèges requis manquants ;
- corrige la déclaration Rust de `MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES` livrée dans `pre.008-fix-001`.
- remplace le type ambigu `MtSolanaProgramMetadataMaterializer` par `MtMetadataSolanaProgramMaterializer` et retire le wrapper générique `MtMetadataMaterializer` ;
- ajoute `MtMetadataMetaplexTokenMetadataMaterializer` et `MtMetadataToken2022Materializer`, chacun avec ses deux contrats, son identité, son tracing target et un ownership instructionnel exact ;
- conserve séparément les APIs de snapshots Metaplex, Solana Program Metadata et Token-2022, sans confondre fait dinstruction et état autoritatif ;
- classe les neuf instructions incorporées Token Metadata et Token Group sous la famille `Metadata`, afin quelles soient possédées par le matérialiseur metadata spécialisé plutôt que par un composant dadministration générique ;
- étend les tests de façade publique et les contrats dinventaire aux trois matérialiseurs metadata spécialisés.
## 0.4.8-pre.007 — exécuteur Solana Program Metadata et structure Metaplex
- ajoute `ExMetadataSolanaProgramMetadataExecutor`, les intents typés, les helpers de PDA et les builders wire exacts des neuf instructions stables `0..8` ;
@@ -24,9 +35,9 @@
- remplace les implémentations génériques `core.rs` par des `materializer.rs`, transforme les fichiers parents en façades pures et déplace toutes les familles, surfaces, tables et identités vers les `constants.rs` réexportés jusquà la racine de crate ;
- rend les 14 matérialisateurs réservés réellement neutres sur les deux traits : famille vide constante, refus legacy, liste dévénements vide et résultat contextuel `Ignored` ;
- aligne les routes de logging dexemple sur `compliance.audit`, `transaction.annotations` et `token.accounts`, et ajoute des audits mécaniques empêchant la réintroduction de noms, constantes ou façades non conformes ;
- conserve `MtMetadataMaterializer` comme wrapper de compatibilité du composant canonique `MtSolanaProgramMetadataMaterializer`, sans second `processorName` ni second propriétaire de faits.
- prépare la spécialisation complète des matérialiseurs metadata, finalisée en `0.4.8-pre.008` sans wrapper générique ambigu.
- corrige les warnings de contrats opérationnels en ajoutant des événements `tracing` réels aux matérialisations `fees`, Metaplex Token Metadata et metadata Token-2022, avec `component_name`, `processor_name`, statut, identité de compte ou dinstruction et nombre de sorties ;
- consomme désormais lidentité runtime `MT_METADATA_TOKEN_2022_COMPONENT_NAME` dans limplémentation state-only au lieu de la limiter aux réexports, et étend les audits pour refuser tout tracing target opérationnel déclaré mais inutilisé ainsi que toute identité de composant absente de son implémentation.
- consomme désormais lidentité runtime `MT_METADATA_TOKEN_2022_COMPONENT_NAME` dans les opérations de snapshot, puis étend les audits pour refuser tout tracing target opérationnel déclaré mais inutilisé ainsi que toute identité de composant absente de son implémentation.
## 0.4.8-pre.006 — matérialisation Solana Program Metadata

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/README.md -->
<!-- version: 25 -->
<!-- version: 26 -->
# kb-lib
@@ -48,7 +48,7 @@ Larbre `src/materializer` suit un contrat homogène :
- une identité runtime `kb-lib.materializer.*` distincte du `processorName` persisté `materializer.*` ;
- des coquilles réservées réellement inactives sur les deux contrats legacy et contextuel.
Linventaire audité comprend 25 composants nommés : neuf matérialisateurs actifs, quatorze coquilles réservées et deux composants metadata state-only. Le détail est consigné dans [laudit de convention des matérialisateurs](../docs/audits/V0_4_8_PRE_007_MATERIALIZER_CONVENTION_AUDIT.md).
Linventaire audité comprend 25 composants nommés : onze matérialisateurs actifs et quatorze coquilles réservées. Les composants metadata Metaplex Token Metadata, Solana Program Metadata et Token-2022 possèdent chacun un type spécialisé, une identité propre et leurs APIs de snapshots lorsque leur état on-chain lexige. Le détail est consigné dans [laudit de convention des matérialisateurs](../docs/audits/V0_4_8_PRE_007_MATERIALIZER_CONVENTION_AUDIT.md).
## Responsabilités

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/USAGE.md -->
<!-- version: 13 -->
<!-- version: 14 -->
# Utilisation de kb-lib
@@ -153,10 +153,16 @@ 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.
Les trois domaines metadata disposent de matérialiseurs instructionnels spécialisés :
- `MtMetadataMetaplexTokenMetadataMaterializer` pour les observations Metaplex de famille metadata ;
- `MtMetadataSolanaProgramMaterializer` pour les neuf instructions stables de `ProgM6…` ;
- `MtMetadataToken2022Materializer` pour les instructions incorporées Token Metadata et Token Group de Token-2022.
Chaque type possède son propre `componentName`, son propre `processorName`, ses familles acceptées et un ownership exact. Les transactions échouées sont refusées. Les faits dinstructions ne remplacent jamais les snapshots autoritatifs lus après exécution.
```rust
let materializer = kb_lib::MtMetadataMaterializer;
let materializer = kb_lib::MtMetadataSolanaProgramMaterializer;
if kb_lib::MtApiEventMaterializer::accepts_observation(&materializer, &observation) {
let result = kb_lib::MtApiEventMaterializer::materialize(&materializer, &observation);
println!("materialization status={:?}", result.status);

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/metadata/solana_program_metadata/instruction.rs
// version: 4
// version: 5
//! Exact contextual instruction decoding for Solana Program Metadata.
@@ -627,9 +627,15 @@ fn validate_accounts(
));
},
};
if account.signer != contract.signer || account.writable != contract.writable {
if contract.signer && !account.signer {
return std::result::Result::Err(format!(
"{} account {position} ({}) has invalid signer/writable flags",
"{} account {position} ({}) is missing the required signer privilege",
parsed.code, contract.role
));
}
if contract.writable && !account.writable {
return std::result::Result::Err(format!(
"{} account {position} ({}) is missing the required writable privilege",
parsed.code, contract.role
));
}
@@ -1160,6 +1166,115 @@ mod tests {
}
}
#[test]
fn transaction_wide_privilege_supersets_are_accepted() {
let cases = [
(
vec![0, 4, 0, 0, 0, 1, 2],
vec![
("buffer", false, true),
("authority", true, true),
(placeholder(), false, false),
],
"write",
),
(
[vec![1], vec![0; 16], vec![1, 0, 1, 0], vec![1]].concat(),
vec![
("metadata", false, true),
("authority", true, true),
("program", false, false),
(placeholder(), false, false),
(placeholder(), false, false),
],
"initialize",
),
(
vec![2, 0],
vec![
("account", false, true),
("authority", true, true),
(placeholder(), false, false),
(placeholder(), false, false),
],
"set_authority",
),
(
vec![3, 1, 0, 1],
vec![
("metadata", false, true),
("authority", true, true),
(placeholder(), false, true),
(placeholder(), false, false),
(placeholder(), false, false),
],
"set_data",
),
(
vec![4],
vec![
("metadata", false, true),
("authority", true, true),
(placeholder(), false, false),
(placeholder(), false, false),
],
"set_immutable",
),
(
vec![5],
vec![
("account", false, true),
("authority", true, true),
(placeholder(), false, false),
(placeholder(), false, false),
("destination", false, true),
("SysvarRent111111111111111111111111111111111", false, false),
],
"trim",
),
(
vec![6],
vec![
("account", false, true),
("authority", true, true),
(placeholder(), false, false),
(placeholder(), false, false),
("destination", false, true),
],
"close",
),
(
[vec![7], vec![8; 16]].concat(),
vec![
("buffer", false, true),
("authority", true, true),
("program", false, false),
(placeholder(), false, false),
(placeholder(), false, false),
],
"allocate",
),
(
vec![8, 32, 0],
vec![
("account", false, true),
("authority", true, true),
(placeholder(), false, false),
(placeholder(), false, false),
],
"extend",
),
];
for (payload, accounts, expected) in cases {
let result = decode(payload.as_slice(), accounts.as_slice());
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded, "{expected}");
assert_eq!(
result.recognized_entry_code.as_deref(),
std::option::Option::Some(expected)
);
}
}
#[test]
fn source_selection_and_account_flags_fail_closed() {
let invalid_write = decode(
@@ -1199,6 +1314,16 @@ mod tests {
],
);
assert_eq!(invalid_flags.status, crate::DcApiDecoderOutcomeStatus::Failed);
let missing_signer = decode(
&[8, 1, 0],
&[
("account", false, true),
("authority", false, true),
(placeholder(), false, false),
(placeholder(), false, false),
],
);
assert_eq!(missing_signer.status, crate::DcApiDecoderOutcomeStatus::Failed);
}
#[test]

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/spl/token_2022/wire.rs
// version: 2
// version: 3
//! Bounded Token-2022 wire, account and authority decoding.
@@ -2532,10 +2532,7 @@ fn event_family(code: &str) -> crate::MdEventFamily {
| "initialize_multisig2"
| "initialize_permanent_delegate"
| "initialize_interest_bearing_mint"
| "update_interest_bearing_rate"
| "update_token_metadata_authority"
| "update_token_group_authority"
| "update_token_group_max_size" => crate::MdEventFamily::Admin,
| "update_interest_bearing_rate" => crate::MdEventFamily::Admin,
"initialize_mint"
| "initialize_mint2"
| "mint_to"
@@ -2564,8 +2561,11 @@ fn event_family(code: &str) -> crate::MdEventFamily {
"initialize_token_metadata"
| "update_token_metadata_field"
| "remove_token_metadata_key"
| "update_token_metadata_authority"
| "emit_token_metadata"
| "initialize_token_group"
| "update_token_group_max_size"
| "update_token_group_authority"
| "initialize_token_group_member" => crate::MdEventFamily::Metadata,
"batch" | "get_account_data_size" | "amount_to_ui_amount" | "ui_amount_to_amount" => {
crate::MdEventFamily::Audit
@@ -2608,3 +2608,23 @@ fn failed(
}],
};
}
#[cfg(test)]
mod metadata_family_tests {
#[test]
fn every_embedded_metadata_and_group_instruction_uses_metadata_family() {
for operation in [
"initialize_token_metadata",
"update_token_metadata_field",
"remove_token_metadata_key",
"update_token_metadata_authority",
"emit_token_metadata",
"initialize_token_group",
"update_token_group_max_size",
"update_token_group_authority",
"initialize_token_group_member",
] {
assert_eq!(super::event_family(operation), crate::MdEventFamily::Metadata);
}
}
}

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/lib.rs
// version: 36
// version: 37
//! Consolidated decoder, executor, materializer and shared model library.
#![warn(missing_docs)]
@@ -1439,8 +1439,12 @@ pub use self::materializer::MtLifecycleMaterializer;
pub use self::materializer::MtLiquidityMaterializer;
/// Exposes the legacy common business materializer trait.
pub use self::materializer::MtMaterializer;
/// Compatibility wrapper for the Solana Program Metadata materializer.
pub use self::materializer::MtMetadataMaterializer;
/// Metaplex Token Metadata instruction materializer.
pub use self::materializer::MtMetadataMetaplexTokenMetadataMaterializer;
/// Solana Program Metadata instruction materializer.
pub use self::materializer::MtMetadataSolanaProgramMaterializer;
/// SPL Token-2022 embedded metadata and group instruction materializer.
pub use self::materializer::MtMetadataToken2022Materializer;
/// Reserved NFT materializer.
pub use self::materializer::MtNftMaterializer;
/// Reserved oracle materializer.
@@ -1457,8 +1461,6 @@ pub use self::materializer::MtRewardsMaterializer;
pub use self::materializer::MtRiskMaterializer;
/// Reserved routing materializer.
pub use self::materializer::MtRoutingMaterializer;
/// Stable Solana Program Metadata instruction materializer.
pub use self::materializer::MtSolanaProgramMetadataMaterializer;
/// Stable native stake and vote materializer.
pub use self::materializer::MtStakingMaterializer;
/// Stable Token, ATA and Token-2022 account materializer.
@@ -2250,22 +2252,28 @@ pub(crate) use self::materializer::MT_LIQUIDITY_ACCEPTED_FAMILIES;
pub(crate) use self::materializer::MT_LIQUIDITY_COMPONENT_NAME;
/// Crate-root access to `MT_LIQUIDITY_PROCESSOR_NAME`.
pub(crate) use self::materializer::MT_LIQUIDITY_PROCESSOR_NAME;
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES`.
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME`.
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME`.
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME;
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION`.
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION`.
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
/// Crate-root access to `MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES`.
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
/// Crate-root access to `MT_METADATA_TOKEN_2022_COMPONENT_NAME`.
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
/// Crate-root access to `MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES`.
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Crate-root access to `MT_METADATA_TOKEN_2022_PROCESSOR_NAME`.
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
/// Crate-root access to `MT_METADATA_TOKEN_2022_PROJECTION_VERSION`.
@@ -2406,8 +2414,8 @@ pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_FEES;
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_LIFECYCLE;
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA`.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA;
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA`.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM`.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022`.
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022;
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_RISK`.

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/materializer.rs
// version: 14
// version: 15
//! Consolidated materializer modules.
@@ -73,10 +73,12 @@ pub use self::lending::MtLendingMaterializer;
pub use self::lifecycle::MtLifecycleMaterializer;
/// Reserved liquidity materializer.
pub use self::liquidity::MtLiquidityMaterializer;
/// Compatibility wrapper for the Solana Program Metadata materializer.
pub use self::metadata::MtMetadataMaterializer;
/// Stable Solana Program Metadata instruction materializer.
pub use self::metadata::MtSolanaProgramMetadataMaterializer;
/// Metaplex Token Metadata instruction materializer.
pub use self::metadata::MtMetadataMetaplexTokenMetadataMaterializer;
/// Solana Program Metadata instruction materializer.
pub use self::metadata::MtMetadataSolanaProgramMaterializer;
/// SPL Token-2022 embedded metadata and group instruction materializer.
pub use self::metadata::MtMetadataToken2022Materializer;
/// 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.
@@ -272,30 +274,36 @@ pub(crate) use self::liquidity::MT_LIQUIDITY_ACCEPTED_FAMILIES;
pub(crate) use self::liquidity::MT_LIQUIDITY_COMPONENT_NAME;
/// Crate-visible `MT_LIQUIDITY_PROCESSOR_NAME` component constant.
pub(crate) use self::liquidity::MT_LIQUIDITY_PROCESSOR_NAME;
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES` component constant.
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME;
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION` component constant.
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION` component constant.
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
/// Crate-visible `MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES` component constant.
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
/// Crate-visible `MT_METADATA_TOKEN_2022_COMPONENT_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
/// Crate-visible `MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES` component constant.
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Crate-visible `MT_METADATA_TOKEN_2022_PROCESSOR_NAME` component constant.
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
/// Crate-visible `MT_METADATA_TOKEN_2022_PROJECTION_VERSION` component constant.
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_PROJECTION_VERSION;
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA` component constant.
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA;
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA` component constant.
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM` component constant.
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022` component constant.
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022;
/// Crate-visible `MT_NFT_ACCEPTED_FAMILIES` component constant.
@@ -491,10 +499,22 @@ mod tests {
crate::MT_LIQUIDITY_PROCESSOR_NAME,
),
(
&crate::MtSolanaProgramMetadataMaterializer,
&crate::MtSolanaProgramMetadataMaterializer,
crate::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME,
crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
&crate::MtMetadataMetaplexTokenMetadataMaterializer,
&crate::MtMetadataMetaplexTokenMetadataMaterializer,
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME,
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
),
(
&crate::MtMetadataSolanaProgramMaterializer,
&crate::MtMetadataSolanaProgramMaterializer,
crate::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME,
crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
),
(
&crate::MtMetadataToken2022Materializer,
&crate::MtMetadataToken2022Materializer,
crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME,
crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
),
(
&crate::MtNftMaterializer,
@@ -583,22 +603,6 @@ mod tests {
];
}
fn state_only_materializer_contracts() -> &'static [(&'static str, &'static str, &'static str)]
{
return &[
(
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME,
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
crate::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA,
),
(
crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME,
crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
crate::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022,
),
];
}
#[test]
fn every_materializer_uses_the_component_and_processor_name_convention() {
for (legacy, contextual, component_name, processor_name) in materializer_contracts() {
@@ -615,18 +619,6 @@ mod tests {
}
}
#[test]
fn state_only_materializers_keep_runtime_processor_and_tracing_identity_aligned() {
for (component_name, processor_name, tracing_target) in state_only_materializer_contracts()
{
assert_eq!(*tracing_target, *component_name);
assert_eq!(
component_name.strip_prefix("kb-lib."),
std::option::Option::Some(*processor_name)
);
}
}
#[test]
fn reserved_materializers_are_empty_shells() {
let materializers: &[&dyn crate::MtApiEventMaterializer] = &[

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/materializer/metadata.rs
// version: 8
// version: 9
//! `metadata` materializer family.
@@ -7,23 +7,27 @@ mod metaplex_token_metadata;
mod solana_program_metadata;
mod token_2022;
/// Metaplex Token Metadata instruction materializer.
pub use self::metaplex_token_metadata::MtMetadataMetaplexTokenMetadataMaterializer;
/// Materializes one canonical non-Metadata Metaplex account snapshot.
pub use self::metaplex_token_metadata::materializer_metadata_materialize_metaplex_account_snapshot;
/// Materializes one canonical Metaplex Metadata account snapshot.
pub use self::metaplex_token_metadata::materializer_metadata_materialize_metaplex_metadata_snapshot;
/// Compatibility materializer retaining the historical generic metadata type name.
pub use self::solana_program_metadata::MtMetadataMaterializer;
/// Stable Solana Program Metadata instruction materializer.
pub use self::solana_program_metadata::MtSolanaProgramMetadataMaterializer;
/// Solana Program Metadata instruction materializer.
pub use self::solana_program_metadata::MtMetadataSolanaProgramMaterializer;
/// 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;
/// SPL Token-2022 embedded metadata and group instruction materializer.
pub use self::token_2022::MtMetadataToken2022Materializer;
/// Materializes Token-2022 embedded metadata and group snapshots.
pub use self::token_2022::materializer_metadata_materialize_token_2022_snapshot;
/// Event families accepted by the Metaplex Token Metadata instruction materializer.
pub(crate) use self::metaplex_token_metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
/// Stable runtime component name for Metaplex Token Metadata projections.
pub(crate) use self::metaplex_token_metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
/// Stable processor name for Metaplex Token Metadata projections.
@@ -33,17 +37,21 @@ pub(crate) use self::metaplex_token_metadata::MT_METADATA_METAPLEX_TOKEN_METADAT
/// Canonical tracing target for Metaplex Token Metadata materialization.
pub(crate) use self::metaplex_token_metadata::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA;
/// Event families accepted by the Solana Program Metadata instruction materializer.
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
/// Stable runtime component name for Solana Program Metadata projections.
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
/// Stable processor name for Solana Program Metadata projections.
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) use self::solana_program_metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
pub(crate) use self::solana_program_metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
/// Event families accepted by the Token-2022 metadata instruction materializer.
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
/// Stable runtime component name for Token-2022 embedded metadata projections.
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
/// Exact embedded Token Metadata and Token Group instruction ownership.
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Stable processor name for Token-2022 embedded metadata projections.
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
/// Stable Token-2022 embedded metadata projection version.

View File

@@ -1,17 +1,22 @@
// file: kb-lib/src/materializer/metadata/metaplex_token_metadata.rs
// version: 2
// version: 3
//! Metaplex Token Metadata account-state materializer.
mod account;
mod constants;
mod materializer;
mod state;
/// Materializes one canonical non-Metadata Metaplex account snapshot.
pub use self::account::materializer_metadata_materialize_metaplex_account_snapshot;
/// Metaplex Token Metadata instruction materializer.
pub use self::materializer::MtMetadataMetaplexTokenMetadataMaterializer;
/// Materializes one canonical Metaplex Metadata account snapshot.
pub use self::state::materializer_metadata_materialize_metaplex_metadata_snapshot;
/// Event families accepted by the Metaplex Token Metadata instruction materializer.
pub(crate) use self::constants::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
/// Stable runtime component name for Metaplex Token Metadata projections.
pub(crate) use self::constants::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
/// Stable processor name for Metaplex Token Metadata projections.

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/materializer/metadata/metaplex_token_metadata/constants.rs
// version: 4
// version: 6
//! Local constants for the metadata metaplex_token_metadata materializer.
@@ -9,6 +9,9 @@ pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME: &str =
/// Stable processor name persisted by metadata projections.
pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME: &str =
"materializer.metadata.metaplex_token_metadata";
/// Event families accepted by the Metaplex Token Metadata instruction materializer.
pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
&[crate::MdEventFamily::Metadata];
/// Stable projection contract version.
pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION: u32 = 2;
/// Canonical tracing target for the metadata metaplex_token_metadata materializer.

View File

@@ -0,0 +1,234 @@
// file: kb-lib/src/materializer/metadata/metaplex_token_metadata/materializer.rs
// version: 1
//! Metaplex Token Metadata instruction materialization.
/// Metaplex Token Metadata instruction materializer.
#[derive(Clone, Debug, Default)]
pub struct MtMetadataMetaplexTokenMetadataMaterializer;
impl crate::MtMaterializer for crate::MtMetadataMetaplexTokenMetadataMaterializer {
fn materializer_name(&self) -> &'static str {
return crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
}
fn materializer_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
return event.event_family == crate::MdEventFamily::Metadata
&& event.program_id.0 == kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& event.surface_code.0 == crate::DC_METADATA_MTM_SURFACE_CODE
&& instruction_contract(event.event_name.0.as_str()).is_some();
}
fn materialize_event(
&self,
event: &crate::MdDecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
if !crate::MtMaterializer::accepts_event(self, event) {
return std::result::Result::Ok(std::vec::Vec::new());
}
return std::result::Result::Ok(std::vec![crate::MdMaterializedEvent {
signature: event.signature.clone(),
slot: event.slot,
decoded_family: event.event_family,
materialized_family: crate::MdMaterializedEventFamily::Metadata,
}]);
}
}
impl crate::MtApiEventMaterializer for crate::MtMetadataMetaplexTokenMetadataMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME.to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return crate::MT_METADATA_METAPLEX_TOKEN_METADATA_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_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& observation.event.surface_code.0 == crate::DC_METADATA_MTM_SURFACE_CODE
&& instruction_contract(observation.event.event_name.0.as_str()).is_some()
&& payload_contract_matches(observation);
}
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_metaplex_token_metadata_refused",
"failed or uncommitted Metaplex Token Metadata instructions cannot create metadata outputs",
);
}
let operation = observation.event.event_name.0.as_str();
let (_, historical) = match instruction_contract(operation) {
std::option::Option::Some(value) => value,
std::option::Option::None => return crate::MtApiMaterializerExecutionResult::ignored(),
};
let deprecated = operation.starts_with("deprecated_");
let output = crate::MtApiMaterializedOutput {
output_key: format!(
"metaplex_token_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_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION,
"domain": "metaplex_token_metadata",
"projectionKind": "committed_instruction_fact",
"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,
"historical": historical,
"deprecated": deprecated,
"authoritativeFinalStateCaptured": false,
"stateProjectionAuthority": "post_execution_account_snapshot",
"parameters": observation.payload_json.get("parameters").cloned().unwrap_or(serde_json::Value::Null),
"accounts": observation.payload_json.get("accounts").cloned().unwrap_or(serde_json::Value::Null),
"decodedPayload": observation.payload_json.clone(),
"provenance": {
"processorName": crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"decoderProof": observation.proof.clone()
}
}),
};
tracing::debug!(
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA,
component_name = crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME,
processor_name = crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
action = "materialize_metaplex_token_metadata_instruction",
operation = operation,
historical = historical,
deprecated = deprecated,
signature = %observation.event.signature.0,
instruction_path = %observation.event.instruction_path.0,
output_count = 1_usize,
"materialize committed Metaplex Token Metadata instruction"
);
return crate::MtApiMaterializerExecutionResult {
status: crate::MtApiMaterializerOutcomeStatus::Inserted,
outputs: std::vec![output],
diagnostics: std::vec::Vec::new(),
};
}
}
fn instruction_contract(operation: &str) -> std::option::Option<(u8, bool)> {
return crate::DC_METADATA_MTM_INSTRUCTION_ENTRIES
.iter()
.find(|(_, code, _)| return *code == operation)
.map(|(discriminator, _, historical)| return (*discriminator, *historical));
}
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_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
);
}
#[cfg(test)]
mod tests {
fn observation(operation: &str, committed: bool) -> crate::DcApiDecodedObservation {
return crate::DcApiDecodedObservation {
event_key: format!("metaplex_token_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_METAPLEX_TOKEN_METADATA_PROGRAM_ID.to_string(),
),
protocol_code: crate::MdProtocolCode(
crate::DC_METADATA_MTM_SURFACE_CODE.to_string(),
),
surface_code: crate::MdSurfaceCode(crate::DC_METADATA_MTM_SURFACE_CODE.to_string()),
event_code: crate::MdEventCode(format!(
"{}.{}",
crate::DC_METADATA_MTM_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_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
"instruction": operation,
"parameters": {},
"accounts": []
}),
transaction_failed: !committed,
transaction_error: std::option::Option::None,
observation_committed: committed,
proof: crate::DcApiDecoderProof {
kind: crate::DcApiDecoderProofKind::Manual,
confidence: crate::MdDecoderConfidence::ManualExact,
evidence: std::vec!["wire".to_string()],
},
};
}
#[test]
fn every_decoded_instruction_has_one_metadata_owner() {
let materializer = crate::MtMetadataMetaplexTokenMetadataMaterializer;
for (_, operation, historical) in crate::DC_METADATA_MTM_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["historical"], historical);
assert_eq!(
result.outputs[0].payload_json["deprecated"],
operation.starts_with("deprecated_")
);
}
}
#[test]
fn failed_and_foreign_observations_do_not_create_outputs() {
let materializer = crate::MtMetadataMetaplexTokenMetadataMaterializer;
let failed = observation("create_metadata_account_v3", false);
let refused = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
assert_eq!(refused.status, crate::MtApiMaterializerOutcomeStatus::Refused);
let mut foreign = observation("create_metadata_account_v3", 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);
}
}

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/materializer/metadata/solana_program_metadata.rs
// version: 2
// version: 3
//! Solana Program Metadata materialization surface.
@@ -7,10 +7,8 @@ mod constants;
mod materializer;
mod state;
/// Compatibility materializer retaining the historical generic metadata type name.
pub use self::materializer::MtMetadataMaterializer;
/// Stable Solana Program Metadata instruction materializer.
pub use self::materializer::MtSolanaProgramMetadataMaterializer;
/// Solana Program Metadata instruction materializer.
pub use self::materializer::MtMetadataSolanaProgramMaterializer;
/// 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.
@@ -19,12 +17,12 @@ pub use self::state::materializer_metadata_materialize_solana_program_metadata_b
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_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
/// Stable runtime component name for Solana Program Metadata projections.
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
/// Stable processor name for Solana Program Metadata projections.
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) use self::constants::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
pub(crate) use self::constants::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;

View File

@@ -4,15 +4,15 @@
//! Local constants for the Solana Program Metadata materializer.
/// Stable runtime component name for Solana Program Metadata materialization.
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME: &str =
pub(crate) const MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME: &str =
"kb-lib.materializer.metadata.solana_program_metadata";
/// Stable processor name persisted by Solana Program Metadata projections.
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME: &str =
pub(crate) const MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME: &str =
"materializer.metadata.solana_program_metadata";
/// Stable projection schema version for Solana Program Metadata outputs.
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION: u32 = 1;
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
pub(crate) const MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION: u32 = 1;
pub(crate) const MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
&[crate::MdEventFamily::Metadata];
/// Canonical tracing target for Solana Program Metadata materialization.
pub(crate) const TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA: &str =
pub(crate) const TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM: &str =
"kb-lib.materializer.metadata.solana_program_metadata";

View File

@@ -1,19 +1,15 @@
// file: kb-lib/src/materializer/metadata/solana_program_metadata/materializer.rs
// version: 4
// version: 5
//! Committed Solana Program Metadata instruction projections.
/// Stable Solana Program Metadata instruction materializer.
#[derive(Clone, Debug, Default)]
pub struct MtSolanaProgramMetadataMaterializer;
pub struct MtMetadataSolanaProgramMaterializer;
/// Compatibility materializer retaining the historical generic metadata type name.
#[derive(Clone, Debug, Default)]
pub struct MtMetadataMaterializer;
impl crate::MtMaterializer for crate::MtSolanaProgramMetadataMaterializer {
impl crate::MtMaterializer for crate::MtMetadataSolanaProgramMaterializer {
fn materializer_name(&self) -> &'static str {
return crate::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
return crate::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
}
fn materializer_version(&self) -> &'static str {
@@ -45,84 +41,16 @@ impl crate::MtMaterializer for crate::MtSolanaProgramMetadataMaterializer {
}
}
impl crate::MtMaterializer for crate::MtMetadataMaterializer {
fn materializer_name(&self) -> &'static str {
return crate::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
}
fn materializer_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
return crate::MtMaterializer::accepts_event(
&crate::MtSolanaProgramMetadataMaterializer,
event,
);
}
fn materialize_event(
&self,
event: &crate::MdDecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
return crate::MtMaterializer::materialize_event(
&crate::MtSolanaProgramMetadataMaterializer,
event,
);
}
}
impl crate::MtApiEventMaterializer for crate::MtMetadataMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiEventMaterializer::identity(
&crate::MtSolanaProgramMetadataMaterializer,
);
}
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return crate::MtApiEventMaterializer::accepted_families(
&crate::MtSolanaProgramMetadataMaterializer,
);
}
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
return crate::MtApiEventMaterializer::accepts_observation(
&crate::MtSolanaProgramMetadataMaterializer,
observation,
);
}
fn transaction_policy(
&self,
family: crate::MdEventFamily,
) -> crate::MtApiMaterializationTransactionPolicy {
return crate::MtApiEventMaterializer::transaction_policy(
&crate::MtSolanaProgramMetadataMaterializer,
family,
);
}
fn materialize(
&self,
observation: &crate::DcApiDecodedObservation,
) -> crate::MtApiMaterializerExecutionResult {
return crate::MtApiEventMaterializer::materialize(
&crate::MtSolanaProgramMetadataMaterializer,
observation,
);
}
}
impl crate::MtApiEventMaterializer for crate::MtSolanaProgramMetadataMaterializer {
impl crate::MtApiEventMaterializer for crate::MtMetadataSolanaProgramMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME.to_string(),
name: crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME.to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return crate::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
return crate::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
}
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
@@ -165,7 +93,7 @@ impl crate::MtApiEventMaterializer for crate::MtSolanaProgramMetadataMaterialize
),
family: crate::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION,
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION,
"domain": "solana_program_metadata",
"projectionKind": "committed_instruction_mutation",
"projectionSemantics": "committed_instruction_fact_non_authoritative_state",
@@ -183,14 +111,14 @@ impl crate::MtApiEventMaterializer for crate::MtSolanaProgramMetadataMaterialize
"externalContentFetched": false,
"externalAccountRead": false,
"provenance": {
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"decoderProof": observation.proof.clone()
}
}),
};
tracing::debug!(
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA,
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM,
action = "materialize_solana_program_metadata_instruction",
operation = operation,
signature = %observation.event.signature.0,
@@ -355,9 +283,9 @@ mod tests {
#[test]
fn every_stable_instruction_has_one_materialized_mutation_fact() {
let materializer = crate::MtSolanaProgramMetadataMaterializer;
let materializer = crate::MtMetadataSolanaProgramMaterializer;
let identity = crate::MtApiEventMaterializer::identity(&materializer);
assert_eq!(identity.name, crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME);
assert_eq!(identity.name, crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME);
for (_, operation) in crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES.iter().copied() {
let value = observation(operation, true);
assert!(crate::MtApiEventMaterializer::accepts_observation(&materializer, &value));
@@ -369,14 +297,14 @@ mod tests {
assert_eq!(result.outputs[0].payload_json["projection"]["replaced"], false);
assert_eq!(
result.outputs[0].payload_json["provenance"]["processorName"],
crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME
crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME
);
}
}
#[test]
fn failed_instruction_is_refused_and_foreign_surface_is_ignored() {
let materializer = crate::MtSolanaProgramMetadataMaterializer;
let materializer = crate::MtMetadataSolanaProgramMaterializer;
let failed = observation("set_data", false);
let failure = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
assert_eq!(failure.status, crate::MtApiMaterializerOutcomeStatus::Refused);
@@ -424,7 +352,7 @@ mod tests {
#[test]
fn trim_keeps_prestable_alias_as_provenance_only() {
let materializer = crate::MtSolanaProgramMetadataMaterializer;
let materializer = crate::MtMetadataSolanaProgramMaterializer;
let value = observation("trim", true);
let result = crate::MtApiEventMaterializer::materialize(&materializer, &value);
assert_eq!(

View File

@@ -63,7 +63,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_buffer_snapshot
output_key: format!("solana_program_metadata_account_state:{}", snapshot.account),
family: crate::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION,
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION,
"domain": "solana_program_metadata",
"projectionKind": "buffer_state",
"projectionSemantics": "authoritative_bounded_owned_account_snapshot",
@@ -83,7 +83,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_buffer_snapshot
"externalAccountRead": false,
"instructionProjectionRole": "mutation_observation_only_no_duplicate_state",
"provenance": {
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"source": "bounded_solana_program_metadata_account_decoder"
}
@@ -150,7 +150,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_metadata_snapsh
output_key: format!("solana_program_metadata_account_state:{}", snapshot.account),
family: crate::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION,
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION,
"domain": "solana_program_metadata",
"projectionKind": "metadata_state",
"projectionSemantics": "authoritative_bounded_owned_account_snapshot",
@@ -177,7 +177,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_metadata_snapsh
"externalAccountRead": false,
"instructionProjectionRole": "mutation_observation_only_no_duplicate_state",
"provenance": {
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"source": "bounded_solana_program_metadata_account_decoder"
}

View File

@@ -1,16 +1,23 @@
// file: kb-lib/src/materializer/metadata/token_2022.rs
// version: 2
// version: 3
//! Embedded SPL Token-2022 metadata materialization surface.
mod constants;
mod materializer;
mod state;
/// SPL Token-2022 embedded metadata and group instruction materializer.
pub use self::materializer::MtMetadataToken2022Materializer;
/// Materializes Token-2022 embedded metadata and group snapshots.
pub use self::state::materializer_metadata_materialize_token_2022_snapshot;
/// Event families accepted by the Token-2022 metadata instruction materializer.
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
/// Stable runtime component name for Token-2022 embedded metadata projections.
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
/// Exact embedded Token Metadata and Token Group instruction ownership.
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Stable processor name for Token-2022 embedded metadata projections.
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
/// Stable Token-2022 embedded metadata projection version.

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/materializer/metadata/token_2022/constants.rs
// version: 3
// version: 4
//! Local constants for the metadata token_2022 materializer.
@@ -8,6 +8,21 @@ pub(crate) const MT_METADATA_TOKEN_2022_COMPONENT_NAME: &str =
"kb-lib.materializer.metadata.token_2022";
/// Stable processor name persisted by metadata projections.
pub(crate) const MT_METADATA_TOKEN_2022_PROCESSOR_NAME: &str = "materializer.metadata.token_2022";
/// Event families accepted by the Token-2022 metadata instruction materializer.
pub(crate) const MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
&[crate::MdEventFamily::Metadata];
/// Exact embedded Token Metadata and Token Group instruction ownership.
pub(crate) const MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES: &[&str] = &[
"initialize_token_metadata",
"update_token_metadata_field",
"remove_token_metadata_key",
"update_token_metadata_authority",
"emit_token_metadata",
"initialize_token_group",
"update_token_group_max_size",
"update_token_group_authority",
"initialize_token_group_member",
];
/// Stable projection contract version.
pub(crate) const MT_METADATA_TOKEN_2022_PROJECTION_VERSION: u32 = 2;
/// Canonical tracing target for the metadata token_2022 materializer.

View File

@@ -0,0 +1,232 @@
// file: kb-lib/src/materializer/metadata/token_2022/materializer.rs
// version: 1
//! SPL Token-2022 embedded metadata and group instruction materialization.
/// SPL Token-2022 embedded metadata and group instruction materializer.
#[derive(Clone, Debug, Default)]
pub struct MtMetadataToken2022Materializer;
impl crate::MtMaterializer for crate::MtMetadataToken2022Materializer {
fn materializer_name(&self) -> &'static str {
return crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
}
fn materializer_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
return event.event_family == crate::MdEventFamily::Metadata
&& event.program_id.0 == kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID
&& event.surface_code.0 == crate::DC_SPL_TOKEN_2022_SURFACE_CODE
&& crate::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES
.iter()
.any(|code| return *code == event.event_name.0.as_str());
}
fn materialize_event(
&self,
event: &crate::MdDecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
if !crate::MtMaterializer::accepts_event(self, event) {
return std::result::Result::Ok(std::vec::Vec::new());
}
return std::result::Result::Ok(std::vec![crate::MdMaterializedEvent {
signature: event.signature.clone(),
slot: event.slot,
decoded_family: event.event_family,
materialized_family: crate::MdMaterializedEventFamily::Metadata,
}]);
}
}
impl crate::MtApiEventMaterializer for crate::MtMetadataToken2022Materializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME.to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return crate::MT_METADATA_TOKEN_2022_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::SPL_TOKEN_2022_PROGRAM_ID
&& observation.event.surface_code.0 == crate::DC_SPL_TOKEN_2022_SURFACE_CODE
&& crate::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES
.iter()
.any(|code| return *code == observation.event.event_name.0.as_str())
&& payload_contract_matches(observation);
}
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_token_2022_metadata_refused",
"failed or uncommitted Token-2022 metadata instructions cannot create metadata outputs",
);
}
let operation = observation.event.event_name.0.as_str();
let output = crate::MtApiMaterializedOutput {
output_key: format!(
"token_2022_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_TOKEN_2022_PROJECTION_VERSION,
"domain": "token_2022_metadata",
"projectionKind": projection_kind(operation),
"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,
"authoritativeFinalStateCaptured": false,
"stateProjectionAuthority": "post_execution_token_2022_mint_snapshot",
"parameters": observation.payload_json.get("parameters").cloned().unwrap_or(serde_json::Value::Null),
"accounts": observation.payload_json.get("accounts").cloned().unwrap_or(serde_json::Value::Null),
"authority": observation.payload_json.get("authority").cloned().unwrap_or(serde_json::Value::Null),
"decodedPayload": observation.payload_json.clone(),
"provenance": {
"processorName": crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"decoderProof": observation.proof.clone()
}
}),
};
tracing::debug!(
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022,
component_name = crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME,
processor_name = crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
action = "materialize_token_2022_metadata_instruction",
operation = operation,
signature = %observation.event.signature.0,
instruction_path = %observation.event.instruction_path.0,
output_count = 1_usize,
"materialize committed Token-2022 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::SPL_TOKEN_2022_PROGRAM_ID);
}
fn projection_kind(operation: &str) -> &'static str {
return match operation {
"initialize_token_metadata" => "metadata_initialized",
"update_token_metadata_field" => "metadata_field_updated",
"remove_token_metadata_key" => "metadata_key_removed",
"update_token_metadata_authority" => "metadata_authority_updated",
"emit_token_metadata" => "metadata_emitted",
"initialize_token_group" => "token_group_initialized",
"update_token_group_max_size" => "token_group_max_size_updated",
"update_token_group_authority" => "token_group_authority_updated",
"initialize_token_group_member" => "token_group_member_initialized",
_ => "unknown",
};
}
#[cfg(test)]
mod tests {
fn observation(operation: &str, committed: bool) -> crate::DcApiDecodedObservation {
return crate::DcApiDecodedObservation {
event_key: format!("token_2022:{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::SPL_TOKEN_2022_PROGRAM_ID.to_string(),
),
protocol_code: crate::MdProtocolCode(
crate::DC_SPL_TOKEN_2022_SURFACE_CODE.to_string(),
),
surface_code: crate::MdSurfaceCode(
crate::DC_SPL_TOKEN_2022_SURFACE_CODE.to_string(),
),
event_code: crate::MdEventCode(format!(
"{}.{}",
crate::DC_SPL_TOKEN_2022_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::SPL_TOKEN_2022_PROGRAM_ID,
"instruction": operation,
"parameters": {},
"accounts": [],
"authority": null
}),
transaction_failed: !committed,
transaction_error: std::option::Option::None,
observation_committed: committed,
proof: crate::DcApiDecoderProof {
kind: crate::DcApiDecoderProofKind::Manual,
confidence: crate::MdDecoderConfidence::ManualExact,
evidence: std::vec!["wire".to_string()],
},
};
}
#[test]
fn every_embedded_metadata_and_group_instruction_has_one_owner() {
let materializer = crate::MtMetadataToken2022Materializer;
for operation in crate::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES {
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);
}
}
#[test]
fn failed_and_non_metadata_observations_do_not_create_outputs() {
let materializer = crate::MtMetadataToken2022Materializer;
let failed = observation("initialize_token_metadata", false);
let refused = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
assert_eq!(refused.status, crate::MtApiMaterializerOutcomeStatus::Refused);
let mut unrelated = observation("initialize_token_metadata", true);
unrelated.event.event_name = crate::MdEventName("transfer_checked".to_string());
unrelated.payload_json["instruction"] =
serde_json::Value::String("transfer_checked".to_string());
let ignored = crate::MtApiEventMaterializer::materialize(&materializer, &unrelated);
assert_eq!(ignored.status, crate::MtApiMaterializerOutcomeStatus::Ignored);
}
}

View File

@@ -1,5 +1,5 @@
// file: kb-lib/tests/external_materializer_api.rs
// version: 7
// version: 8
//! Downstream-style compilation contract for externally implemented materializers.
@@ -50,8 +50,9 @@ 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::MtSolanaProgramMetadataMaterializer>();
assert_event_materializer::<kb_lib::MtMetadataMetaplexTokenMetadataMaterializer>();
assert_event_materializer::<kb_lib::MtMetadataSolanaProgramMaterializer>();
assert_event_materializer::<kb_lib::MtMetadataToken2022Materializer>();
assert_event_materializer::<kb_lib::MtLiquidityMaterializer>();
assert_event_materializer::<kb_lib::MtNftMaterializer>();
assert_event_materializer::<kb_lib::MtOracleMaterializer>();
@@ -71,8 +72,9 @@ fn external_materializer_uses_only_the_public_kb_lib_contract() {
assert_legacy_materializer::<kb_lib::MtGovernanceMaterializer>();
assert_legacy_materializer::<kb_lib::MtLendingMaterializer>();
assert_legacy_materializer::<kb_lib::MtLiquidityMaterializer>();
assert_legacy_materializer::<kb_lib::MtMetadataMaterializer>();
assert_legacy_materializer::<kb_lib::MtSolanaProgramMetadataMaterializer>();
assert_legacy_materializer::<kb_lib::MtMetadataMetaplexTokenMetadataMaterializer>();
assert_legacy_materializer::<kb_lib::MtMetadataSolanaProgramMaterializer>();
assert_legacy_materializer::<kb_lib::MtMetadataToken2022Materializer>();
assert_legacy_materializer::<kb_lib::MtNftMaterializer>();
assert_legacy_materializer::<kb_lib::MtOracleMaterializer>();
assert_legacy_materializer::<kb_lib::MtOrderbookMaterializer>();