This commit is contained in:
2026-07-23 16:37:12 +02:00
parent 99c345f2f2
commit 0da75c1311
2159 changed files with 230833 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
// file: kb_materializer_token_accounts/src/constants.rs
// version: 3
//! Local constants for classic SPL Token account projections.
/// Canonical tracing target for this crate.
pub(crate) const TRACING_TARGET: &str = "kb_materializer_token_accounts";
/// Stable processor name persisted by the replay ledger.
pub(crate) const PROCESSOR_NAME: &str = "spl_token_accounts";
/// Stable projection payload contract version.
pub(crate) const PROJECTION_VERSION: u32 = 3;

View File

@@ -0,0 +1,22 @@
// file: kb_materializer_token_accounts/src/lib.rs
// version: 8
//! Materializer crate for classic SPL Token mutations and ATA lifecycle facts.
#![warn(missing_docs)]
#![deny(unreachable_pub)]
#![forbid(unsafe_code)]
mod constants;
mod materializer;
/// Stable processor name persisted by the replay ledger.
pub(crate) use crate::constants::PROCESSOR_NAME;
/// Stable projection payload contract version.
pub(crate) use crate::constants::PROJECTION_VERSION;
/// Canonical tracing target for this crate.
pub(crate) use crate::constants::TRACING_TARGET;
/// Stable committed classic SPL Token mutation and ATA lifecycle materializer.
pub use crate::materializer::TokenAccountsMaterializer;
/// Materialize one bounded Token-2022 Mint, Account, or Multisig state snapshot.
pub use crate::materializer::materialize_token_2022_state_snapshot;

View File

@@ -0,0 +1,835 @@
// file: kb_materializer_token_accounts/src/materializer.rs
// version: 9
//! Stable committed SPL Token mutation and ATA lifecycle projections.
const ACCEPTED_FAMILIES: &[kb_model::EventFamily] = &[
kb_model::EventFamily::TokenAccount,
kb_model::EventFamily::TokenMint,
kb_model::EventFamily::TokenBurn,
kb_model::EventFamily::Lifecycle,
];
const MUTATION_ENTRIES: &[&str] = &[
"initialize_mint",
"initialize_mint2",
"initialize_account",
"initialize_account2",
"initialize_account3",
"transfer",
"transfer_checked",
"approve",
"approve_checked",
"revoke",
"mint_to",
"mint_to_checked",
"burn",
"burn_checked",
"close_account",
"freeze_account",
"thaw_account",
"sync_native",
"initialize_immutable_owner",
"withdraw_excess_lamports",
"unwrap_lamports",
"initialize_non_transferable_mint",
"reallocate",
];
const ATA_LIFECYCLE_ENTRIES: &[(&str, &str)] = &[
("create", "ata_created"),
("create_idempotent", "ata_created_or_reused_idempotently"),
("recover_nested", "nested_ata_recovered"),
];
/// Stable committed classic SPL Token account and mint mutation materializer.
#[derive(Clone, Debug, Default)]
pub struct TokenAccountsMaterializer;
impl kb_materializer_api::Materializer for crate::TokenAccountsMaterializer {
fn materializer_name(&self) -> &'static str {
return "kb_materializer_token_accounts";
}
fn materializer_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn accepts_event(&self, event: &kb_model::DecodedProtocolEvent) -> bool {
return accepts_event(event);
}
fn materialize_event(
&self,
_event: &kb_model::DecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<kb_model::MaterializedEvent>> {
return std::result::Result::Ok(std::vec::Vec::new());
}
}
impl kb_materializer_api::EventMaterializer for crate::TokenAccountsMaterializer {
fn identity(&self) -> kb_materializer_api::MaterializerIdentity {
return kb_materializer_api::MaterializerIdentity {
name: crate::PROCESSOR_NAME.to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn accepted_families(&self) -> &'static [kb_model::EventFamily] {
return ACCEPTED_FAMILIES;
}
fn accepts_observation(&self, observation: &kb_decoder_api::DecodedObservation) -> bool {
return accepts_event(&observation.event);
}
fn transaction_policy(
&self,
_family: kb_model::EventFamily,
) -> kb_materializer_api::MaterializationTransactionPolicy {
return kb_materializer_api::MaterializationTransactionPolicy::SuccessfulCommittedOnly;
}
fn materialize(
&self,
observation: &kb_decoder_api::DecodedObservation,
) -> kb_materializer_api::MaterializerExecutionResult {
if !accepts_event(&observation.event) {
return kb_materializer_api::MaterializerExecutionResult::ignored();
}
if observation.transaction_failed || !observation.observation_committed {
return kb_materializer_api::MaterializerExecutionResult::refused(
"uncommitted_token_account_projection_refused",
"failed or uncommitted SPL Token or ATA observations cannot create mutable outputs",
);
}
if is_ata_event(&observation.event) {
return materialize_ata(observation);
}
let parameters = observation
.payload_json
.get("parameters")
.cloned()
.unwrap_or(serde_json::Value::Null);
let accounts = observation
.payload_json
.get("accounts")
.cloned()
.unwrap_or(serde_json::Value::Null);
let authority = observation
.payload_json
.get("authority")
.cloned()
.unwrap_or(serde_json::Value::Null);
let operation = observation.event.event_name.0.clone();
let output = kb_materializer_api::MaterializedOutput {
output_key: format!("token_account_mutation:{operation}:0"),
family: kb_model::MaterializedEventFamily::TokenAccount,
payload_json: serde_json::json!({
"projectionVersion": crate::PROJECTION_VERSION,
"domain": "spl_token_account_mutation",
"projectionSemantics": "committed_instruction_mutation_not_final_account_snapshot",
"idempotenceKey": format!(
"spl_token:{}:{}:{}",
observation.event.signature.0,
observation.event.instruction_path.0,
operation
),
"operation": operation,
"signature": observation.event.signature.0.clone(),
"slot": observation.event.slot.0,
"instructionPath": observation.event.instruction_path.0.clone(),
"programId": observation.event.program_id.0.clone(),
"mint": account_key_for_role(&accounts, "mint"),
"amountRaw": parameters.get("amountRaw").cloned().unwrap_or(serde_json::Value::Null),
"decimals": parameters.get("decimals").cloned().unwrap_or(serde_json::Value::Null),
"parameters": parameters,
"accounts": accounts,
"authority": authority,
"committed": true,
"transactionFinalAccountStateCaptured": false,
"coreBalanceChangesDuplicated": false,
"provenance": {
"processorName": crate::PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"sourceSurface": observation.event.surface_code.0.clone(),
"sourceEventCode": observation.event.event_code.0.clone(),
"sourceEventKey": observation.event_key.clone()
}
}),
};
tracing::debug!(
target: crate::TRACING_TARGET,
action = "materialize_token_account_mutation",
signature = %observation.event.signature.0,
instruction_path = %observation.event.instruction_path.0,
operation = %observation.event.event_name.0,
"materialize committed classic SPL Token mutation"
);
return kb_materializer_api::MaterializerExecutionResult {
status: kb_materializer_api::MaterializerOutcomeStatus::Inserted,
outputs: std::vec![output],
diagnostics: std::vec::Vec::new(),
};
}
}
fn accepts_event(event: &kb_model::DecodedProtocolEvent) -> bool {
let token_program = (event.program_id.0 == kb_program_ids::SPL_TOKEN_PROGRAM_ID
&& event.surface_code.0 == "spl_token")
|| (event.program_id.0 == kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID
&& event.surface_code.0 == "spl_token_2022");
let token_mutation = token_program && MUTATION_ENTRIES.contains(&event.event_name.0.as_str());
let ata = is_ata_event(event);
return ACCEPTED_FAMILIES.contains(&event.event_family) && (token_mutation || ata);
}
fn is_ata_event(event: &kb_model::DecodedProtocolEvent) -> bool {
return event.program_id.0 == kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID
&& event.surface_code.0 == "spl_associated_token_account"
&& event.event_family == kb_model::EventFamily::Lifecycle
&& ATA_LIFECYCLE_ENTRIES
.iter()
.any(|(entry, _)| return *entry == event.event_name.0);
}
fn materialize_ata(
observation: &kb_decoder_api::DecodedObservation,
) -> kb_materializer_api::MaterializerExecutionResult {
let operation = observation.event.event_name.0.as_str();
let addresses = match observation.payload_json.get("addresses") {
std::option::Option::Some(value) if value.is_object() => value,
_ => {
return kb_materializer_api::MaterializerExecutionResult::refused(
"ata_addresses_missing",
"committed ATA lifecycle projection requires the decoded address contract",
);
},
};
let validation = validate_ata_addresses(operation, addresses);
if let std::result::Result::Err((code, message)) = validation {
return kb_materializer_api::MaterializerExecutionResult::refused(code, message);
}
let lifecycle_kind =
match ATA_LIFECYCLE_ENTRIES.iter().find(|(entry, _)| return *entry == operation) {
std::option::Option::Some((_, value)) => *value,
std::option::Option::None => {
return kb_materializer_api::MaterializerExecutionResult::ignored();
},
};
let associated_token_account = if operation == "recover_nested" {
observed_address(addresses, "nestedAssociatedTokenAccount")
} else {
observed_address(addresses, "associatedTokenAccount")
};
let token_program = addresses
.get("tokenProgram")
.and_then(|value| return value.get("programId"))
.cloned()
.unwrap_or(serde_json::Value::Null);
let wallet = addresses.get("walletOwner").cloned().unwrap_or(serde_json::Value::Null);
let mint = if operation == "recover_nested" {
addresses.get("nestedMint").cloned().unwrap_or(serde_json::Value::Null)
} else {
addresses.get("mint").cloned().unwrap_or(serde_json::Value::Null)
};
let output = kb_materializer_api::MaterializedOutput {
output_key: format!("ata_lifecycle:{lifecycle_kind}:0"),
family: kb_model::MaterializedEventFamily::TokenAccount,
payload_json: serde_json::json!({
"projectionVersion": crate::PROJECTION_VERSION,
"domain": "spl_associated_token_account_lifecycle",
"projectionSemantics": "committed_associated_address_lifecycle_not_token_state_snapshot",
"idempotenceKey": format!(
"ata:{}:{}:{}:{}:{}",
observation.event.signature.0,
observation.event.instruction_path.0,
observation.event.program_id.0,
lifecycle_kind,
associated_token_account.as_str().unwrap_or("")
),
"operation": operation,
"lifecycleKind": lifecycle_kind,
"associatedTokenAccount": associated_token_account,
"walletOwner": wallet,
"mint": mint,
"tokenProgramId": token_program,
"fundingAccount": addresses.get("fundingAccount").cloned().unwrap_or(serde_json::Value::Null),
"ownerMint": addresses.get("ownerMint").cloned().unwrap_or(serde_json::Value::Null),
"nestedMint": addresses.get("nestedMint").cloned().unwrap_or(serde_json::Value::Null),
"ownerAssociatedTokenAccount": observed_address(addresses, "ownerAssociatedTokenAccount"),
"nestedAssociatedTokenAccount": observed_address(addresses, "nestedAssociatedTokenAccount"),
"walletNestedMintAssociatedTokenAccount": observed_address(addresses, "walletNestedMintAssociatedTokenAccount"),
"idempotentOutcome": if operation == "create_idempotent" {
"created_or_reused_not_distinguishable_from_parent_instruction_alone"
} else {
"not_applicable"
},
"signature": observation.event.signature.0.clone(),
"slot": observation.event.slot.0,
"instructionPath": observation.event.instruction_path.0.clone(),
"programId": observation.event.program_id.0.clone(),
"committed": true,
"transactionFinalAccountStateCaptured": false,
"tokenBalanceReconstructed": false,
"splTokenCpiMutationsDuplicated": false,
"ownership": {
"ataParent": "associated_address_lifecycle_only",
"splTokenCpi": "initialize_transfer_and_close_mutations"
},
"provenance": {
"processorName": crate::PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"sourceSurface": observation.event.surface_code.0.clone(),
"sourceEventCode": observation.event.event_code.0.clone(),
"sourceEventKey": observation.event_key.clone()
}
}),
};
tracing::debug!(
target: crate::TRACING_TARGET,
action = "materialize_ata_lifecycle",
signature = %observation.event.signature.0,
instruction_path = %observation.event.instruction_path.0,
operation,
lifecycle_kind,
"materialize committed ATA lifecycle without duplicating SPL Token CPI mutations"
);
return kb_materializer_api::MaterializerExecutionResult {
status: kb_materializer_api::MaterializerOutcomeStatus::Inserted,
outputs: std::vec![output],
diagnostics: std::vec::Vec::new(),
};
}
fn validate_ata_addresses(
operation: &str,
addresses: &serde_json::Value,
) -> std::result::Result<(), (&'static str, &'static str)> {
let token_supported = addresses
.get("tokenProgram")
.and_then(|value| return value.get("supported"))
.and_then(serde_json::Value::as_bool)
== std::option::Option::Some(true);
let token_program_id = addresses
.get("tokenProgram")
.and_then(|value| return value.get("programId"))
.and_then(serde_json::Value::as_str);
let token_program_exact = matches!(
token_program_id,
std::option::Option::Some(kb_program_ids::SPL_TOKEN_PROGRAM_ID)
| std::option::Option::Some(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID)
);
if !token_supported || !token_program_exact {
return std::result::Result::Err((
"ata_token_program_not_supported",
"ATA lifecycle projection requires classic SPL Token or Token-2022",
));
}
let fields: &[&str] = if operation == "recover_nested" {
&[
"ownerAssociatedTokenAccount",
"nestedAssociatedTokenAccount",
"walletNestedMintAssociatedTokenAccount",
]
} else {
&["associatedTokenAccount"]
};
for field in fields {
let valid = addresses
.get(*field)
.and_then(|value| return value.get("valid"))
.and_then(serde_json::Value::as_bool)
== std::option::Option::Some(true);
let observed = observed_address(addresses, field);
if !valid || observed.as_str().is_none_or(|value| return value.is_empty()) {
return std::result::Result::Err((
"ata_derived_address_invalid",
"ATA lifecycle projection requires every canonical address validation to pass",
));
}
}
let identity_fields: &[&str] = if operation == "recover_nested" {
&["walletOwner", "ownerMint", "nestedMint"]
} else {
&["walletOwner", "mint"]
};
if identity_fields.iter().any(|field| {
return addresses
.get(*field)
.and_then(serde_json::Value::as_str)
.is_none_or(|value| return value.is_empty());
}) {
return std::result::Result::Err((
"ata_identity_field_missing",
"ATA lifecycle projection requires wallet and mint identities",
));
}
return std::result::Result::Ok(());
}
fn observed_address(addresses: &serde_json::Value, field: &str) -> serde_json::Value {
return addresses
.get(field)
.and_then(|value| return value.get("observed"))
.cloned()
.unwrap_or(serde_json::Value::Null);
}
fn account_key_for_role(accounts: &serde_json::Value, role: &str) -> serde_json::Value {
let value = accounts.as_array().and_then(|rows| {
return rows.iter().find_map(|row| {
if row.get("role").and_then(serde_json::Value::as_str)
!= std::option::Option::Some(role)
{
return std::option::Option::None;
}
return row.get("accountKey").and_then(serde_json::Value::as_str);
});
});
return match value {
std::option::Option::Some(account_key) => {
serde_json::Value::String(account_key.to_string())
},
std::option::Option::None => serde_json::Value::Null,
};
}
/// Materialize one already parsed Token-2022 account snapshot without inferring hidden state.
pub fn materialize_token_2022_state_snapshot(
account_key: &str,
slot: u64,
state: &kb_decoder_spl_token_2022::state::Token2022State,
) -> std::result::Result<kb_materializer_api::MaterializedOutput, String> {
if account_key.is_empty() {
return std::result::Result::Err(
"Token-2022 state snapshot requires a non-empty account key".to_string(),
);
}
let kind = match state.kind {
kb_decoder_spl_token_2022::state::Token2022StateKind::Mint => "mint",
kb_decoder_spl_token_2022::state::Token2022StateKind::Account => "account",
kb_decoder_spl_token_2022::state::Token2022StateKind::Multisig => "multisig",
};
let extensions = state
.extensions
.iter()
.map(|entry| {
return serde_json::json!({
"extensionType": entry.extension_type,
"extensionName": entry.extension_name,
"valueHex": entry.value_hex,
"valueFields": entry.value_fields,
});
})
.collect::<std::vec::Vec<_>>();
let extension_names = state
.extensions
.iter()
.map(|entry| return entry.extension_name)
.collect::<std::vec::Vec<_>>();
let contains_confidential_state = state.extensions.iter().any(|entry| {
return entry.extension_name.starts_with("confidential_")
|| entry.extension_name == "confidential_mint_burn";
});
return std::result::Result::Ok(kb_materializer_api::MaterializedOutput {
output_key: format!("token_2022_state_snapshot:{account_key}:{slot}"),
family: kb_model::MaterializedEventFamily::TokenAccount,
payload_json: serde_json::json!({
"projectionVersion": crate::PROJECTION_VERSION,
"domain": "spl_token_2022_account_state",
"projectionSemantics": "authoritative_bounded_account_snapshot",
"idempotenceKey": format!("token_2022_state:{account_key}:{slot}"),
"accountKey": account_key,
"slot": slot,
"programId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
"stateKind": kind,
"baseFields": state.base_fields,
"baseHex": state.base_hex,
"accountType": state.account_type,
"extensionCount": state.extensions.len(),
"extensionNames": extension_names,
"extensions": extensions,
"containsConfidentialState": contains_confidential_state,
"confidentialValuesDecrypted": false,
"finalAccountStateCaptured": true,
"provenance": {
"processorName": crate::PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"source": "bounded_token_2022_state_parser"
}
}),
});
}
#[cfg(test)]
mod tests {
fn observation(
entry: &str,
family: kb_model::EventFamily,
failed: bool,
) -> kb_decoder_api::DecodedObservation {
return kb_decoder_api::DecodedObservation {
event_key: format!("token:{entry}:0"),
event: kb_model::DecodedProtocolEvent {
signature: kb_model::Signature("signature".to_string()),
slot: kb_model::Slot(42),
instruction_path: kb_model::InstructionPath("1/0".to_string()),
program_id: kb_model::ProgramId(kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string()),
protocol_code: kb_model::ProtocolCode("spl_token".to_string()),
surface_code: kb_model::SurfaceCode("spl_token".to_string()),
event_code: kb_model::EventCode(format!("spl_token.{entry}")),
event_name: kb_model::EventName(entry.to_string()),
event_family: family,
source_kind: kb_model::EventSourceKind::InnerInstruction,
confidence: kb_model::DecoderConfidence::ManualExact,
},
payload_json: serde_json::json!({
"parameters": {"amountRaw":"18446744073709551615","decimals":9},
"accounts": [{"role":"mint","accountKey":"mint111"}],
"authority": {"form":"single"}
}),
transaction_failed: failed,
transaction_error: if failed {
std::option::Option::Some(serde_json::json!({"error":"failed"}))
} else {
std::option::Option::None
},
observation_committed: !failed,
proof: kb_decoder_api::DecoderProof {
kind: kb_decoder_api::DecoderProofKind::Manual,
confidence: kb_model::DecoderConfidence::ManualExact,
evidence: std::vec!["fixture".to_string()],
},
};
}
fn token_2022_observation(
entry: &str,
family: kb_model::EventFamily,
failed: bool,
) -> kb_decoder_api::DecodedObservation {
let mut observation = observation(entry, family, failed);
observation.event.program_id =
kb_model::ProgramId(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID.to_string());
observation.event.protocol_code = kb_model::ProtocolCode("spl_token_2022".to_string());
observation.event.surface_code = kb_model::SurfaceCode("spl_token_2022".to_string());
observation.event.event_code = kb_model::EventCode(format!("spl_token_2022.{entry}"));
observation.event_key = format!("token_2022:{entry}:0");
return observation;
}
fn ata_observation(
entry: &str,
failed: bool,
valid: bool,
) -> kb_decoder_api::DecodedObservation {
let addresses = if entry == "recover_nested" {
serde_json::json!({
"tokenProgram": {
"programId": kb_program_ids::SPL_TOKEN_PROGRAM_ID,
"kind": "spl_token_classic",
"supported": true
},
"ownerAssociatedTokenAccount": {"expected":"ownerAta","observed":"ownerAta","valid":valid},
"nestedAssociatedTokenAccount": {"expected":"nestedAta","observed":"nestedAta","valid":valid},
"walletNestedMintAssociatedTokenAccount": {"expected":"destinationAta","observed":"destinationAta","valid":valid},
"walletOwner": "wallet111",
"ownerMint": "ownerMint111",
"nestedMint": "nestedMint111"
})
} else {
serde_json::json!({
"tokenProgram": {
"programId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
"kind": "token_2022",
"supported": true
},
"associatedTokenAccount": {"expected":"ata111","observed":"ata111","valid":valid},
"fundingAccount": "payer111",
"walletOwner": "wallet111",
"mint": "mint111"
})
};
return kb_decoder_api::DecodedObservation {
event_key: format!("ata:{entry}:0"),
event: kb_model::DecodedProtocolEvent {
signature: kb_model::Signature("signature".to_string()),
slot: kb_model::Slot(42),
instruction_path: kb_model::InstructionPath("0".to_string()),
program_id: kb_model::ProgramId(
kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID.to_string(),
),
protocol_code: kb_model::ProtocolCode("spl_associated_token_account".to_string()),
surface_code: kb_model::SurfaceCode("spl_associated_token_account".to_string()),
event_code: kb_model::EventCode(format!("spl_associated_token_account.{entry}")),
event_name: kb_model::EventName(entry.to_string()),
event_family: kb_model::EventFamily::Lifecycle,
source_kind: kb_model::EventSourceKind::Instruction,
confidence: kb_model::DecoderConfidence::ManualExact,
},
payload_json: serde_json::json!({"addresses":addresses}),
transaction_failed: failed,
transaction_error: std::option::Option::None,
observation_committed: !failed,
proof: kb_decoder_api::DecoderProof {
kind: kb_decoder_api::DecoderProofKind::Manual,
confidence: kb_model::DecoderConfidence::ManualExact,
evidence: std::vec!["fixture".to_string()],
},
};
}
#[test]
fn committed_checked_transfer_preserves_exact_amount_mint_and_path() {
let observation =
observation("transfer_checked", kb_model::EventFamily::TokenAccount, false);
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, kb_materializer_api::MaterializerOutcomeStatus::Inserted);
assert_eq!(result.outputs[0].payload_json["amountRaw"], "18446744073709551615");
assert_eq!(result.outputs[0].payload_json["mint"], "mint111");
assert_eq!(result.outputs[0].payload_json["instructionPath"], "1/0");
assert_eq!(result.outputs[0].payload_json["transactionFinalAccountStateCaptured"], false);
}
#[test]
fn committed_token_2022_transfer_has_the_same_single_projection_owner() {
let observation =
token_2022_observation("transfer_checked", kb_model::EventFamily::TokenAccount, false);
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, kb_materializer_api::MaterializerOutcomeStatus::Inserted);
assert_eq!(result.outputs.len(), 1);
assert_eq!(result.outputs[0].payload_json["operation"], "transfer_checked");
assert_eq!(
result.outputs[0].payload_json["programId"],
kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID
);
}
#[test]
fn failed_mutation_is_refused() {
let observation = observation("burn", kb_model::EventFamily::TokenBurn, true);
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, kb_materializer_api::MaterializerOutcomeStatus::Refused);
assert!(result.outputs.is_empty());
}
#[test]
fn batch_parent_admin_and_conversion_events_are_not_duplicated() {
for (entry, family) in [
("batch", kb_model::EventFamily::Audit),
("set_authority", kb_model::EventFamily::Admin),
("amount_to_ui_amount", kb_model::EventFamily::Audit),
] {
let observation = observation(entry, family, false);
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, kb_materializer_api::MaterializerOutcomeStatus::Ignored);
}
}
#[test]
fn every_ata_variant_has_one_exact_lifecycle_projection() {
for (entry, expected_kind, expected_ata, expected_token_program) in [
("create", "ata_created", "ata111", kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID),
(
"create_idempotent",
"ata_created_or_reused_idempotently",
"ata111",
kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
),
(
"recover_nested",
"nested_ata_recovered",
"nestedAta",
kb_program_ids::SPL_TOKEN_PROGRAM_ID,
),
] {
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&ata_observation(entry, false, true),
);
assert_eq!(result.status, kb_materializer_api::MaterializerOutcomeStatus::Inserted);
assert_eq!(result.outputs.len(), 1);
assert_eq!(result.outputs[0].payload_json["lifecycleKind"], expected_kind);
assert_eq!(result.outputs[0].payload_json["associatedTokenAccount"], expected_ata);
assert_eq!(result.outputs[0].payload_json["tokenProgramId"], expected_token_program);
assert_eq!(result.outputs[0].payload_json["tokenBalanceReconstructed"], false);
assert_eq!(result.outputs[0].payload_json["splTokenCpiMutationsDuplicated"], false);
}
}
#[test]
fn idempotent_parent_does_not_invent_created_or_reused_branch() {
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&ata_observation("create_idempotent", false, true),
);
assert_eq!(
result.outputs[0].payload_json["idempotentOutcome"],
"created_or_reused_not_distinguishable_from_parent_instruction_alone"
);
assert!(result.outputs[0].payload_json.get("reused").is_none());
assert!(result.outputs[0].payload_json.get("created").is_none());
}
#[test]
fn uncommitted_or_invalid_ata_lifecycle_is_refused() {
for observation in [
ata_observation("create", true, true),
ata_observation("recover_nested", false, false),
] {
let result = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, kb_materializer_api::MaterializerOutcomeStatus::Refused);
assert!(result.outputs.is_empty());
}
}
#[test]
fn ata_parent_and_classic_token_cpi_children_own_distinct_facts() {
let parent = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&ata_observation("recover_nested", false, true),
);
let transfer = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation("transfer", kb_model::EventFamily::TokenAccount, false),
);
let close = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation("close_account", kb_model::EventFamily::TokenAccount, false),
);
assert_eq!(parent.outputs[0].payload_json["lifecycleKind"], "nested_ata_recovered");
assert_eq!(
parent.outputs[0].payload_json["ownership"]["ataParent"],
"associated_address_lifecycle_only"
);
assert!(parent.outputs[0].payload_json.get("amountRaw").is_none());
assert_eq!(transfer.outputs[0].payload_json["operation"], "transfer");
assert_eq!(close.outputs[0].payload_json["operation"], "close_account");
assert_eq!(transfer.outputs[0].payload_json["domain"], "spl_token_account_mutation");
assert_eq!(close.outputs[0].payload_json["domain"], "spl_token_account_mutation");
}
#[test]
fn ata_matrix_and_compiled_token_account_projection_ownership_are_equal() {
let matrix: serde_json::Value = match serde_json::from_str(include_str!(
"../../docs/SPL_ASSOCIATED_TOKEN_ACCOUNT_MATRIX.json"
)) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("ATA matrix is invalid: {error}"),
};
let instructions = match matrix.get("instructions").and_then(serde_json::Value::as_array) {
std::option::Option::Some(value) => value,
std::option::Option::None => panic!("ATA matrix instructions are absent"),
};
for (entry, fact) in super::ATA_LIFECYCLE_ENTRIES {
let row = match instructions.iter().find(|row| {
return row.get("name").and_then(serde_json::Value::as_str)
== std::option::Option::Some(*entry);
}) {
std::option::Option::Some(value) => value,
std::option::Option::None => panic!("ATA matrix entry {entry} is absent"),
};
let expected = format!("token_accounts:{fact}");
assert!(row["authorizedProjections"].as_array().is_some_and(|values| {
return values.iter().any(|value| return value == expected.as_str());
}));
}
let owner = &matrix["materializationContract"]["projectionOwners"][0];
let matrix_facts = match owner["facts"].as_array() {
std::option::Option::Some(values) => values
.iter()
.filter_map(|value| return value.as_str())
.collect::<std::vec::Vec<_>>(),
std::option::Option::None => panic!("ATA token-account owner facts are absent"),
};
let compiled_facts = super::ATA_LIFECYCLE_ENTRIES
.iter()
.map(|(_, fact)| return *fact)
.collect::<std::vec::Vec<_>>();
assert_eq!(matrix_facts, compiled_facts);
}
#[test]
fn second_ata_materialization_is_byte_for_byte_idempotent() {
let observation = ata_observation("create_idempotent", false, true);
let first = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
let second = kb_materializer_api::EventMaterializer::materialize(
&crate::TokenAccountsMaterializer,
&observation,
);
assert_eq!(first, second);
assert_eq!(first.outputs[0].output_key, second.outputs[0].output_key);
assert_eq!(
first.outputs[0].payload_json["idempotenceKey"],
second.outputs[0].payload_json["idempotenceKey"]
);
}
#[test]
fn token_2022_state_snapshot_preserves_base_and_ordered_extensions() {
let state = kb_decoder_spl_token_2022::state::Token2022State {
kind: kb_decoder_spl_token_2022::state::Token2022StateKind::Mint,
base_fields: serde_json::json!({"supply":"42","decimals":9,"initialized":true}),
base_hex: "00".repeat(82),
account_type: std::option::Option::Some(1),
extensions: std::vec![
kb_decoder_spl_token_2022::state::Token2022TlvEntry {
extension_type: 1,
extension_name: "transfer_fee_config",
value_hex: "11".repeat(108),
value_fields: serde_json::json!({"withheldAmount":"7"}),
},
kb_decoder_spl_token_2022::state::Token2022TlvEntry {
extension_type: 4,
extension_name: "confidential_transfer_mint",
value_hex: "22".repeat(65),
value_fields: serde_json::json!({"autoApproveNewAccounts":true}),
},
],
};
let output = match crate::materialize_token_2022_state_snapshot("mint111", 99, &state) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("snapshot failed: {error}"),
};
assert_eq!(output.payload_json["stateKind"], "mint");
assert_eq!(output.payload_json["extensionCount"], 2);
assert_eq!(output.payload_json["extensionNames"][0], "transfer_fee_config");
assert_eq!(output.payload_json["extensionNames"][1], "confidential_transfer_mint");
assert_eq!(output.payload_json["containsConfidentialState"], true);
assert_eq!(output.payload_json["confidentialValuesDecrypted"], false);
assert_eq!(output.payload_json["baseFields"]["supply"], "42");
}
#[test]
fn token_2022_state_snapshot_is_idempotent_and_rejects_missing_identity() {
let state = kb_decoder_spl_token_2022::state::Token2022State {
kind: kb_decoder_spl_token_2022::state::Token2022StateKind::Account,
base_fields: serde_json::json!({"mint":"mint111","owner":"wallet111","amount":"5"}),
base_hex: "00".repeat(165),
account_type: std::option::Option::None,
extensions: std::vec::Vec::new(),
};
let first = crate::materialize_token_2022_state_snapshot("account111", 7, &state);
let second = crate::materialize_token_2022_state_snapshot("account111", 7, &state);
assert_eq!(first, second);
assert!(crate::materialize_token_2022_state_snapshot("", 7, &state).is_err());
}
}