v0.1.0-pre.011

This commit is contained in:
2026-07-24 14:23:58 +02:00
parent 62bc0ffb44
commit 42e8a203ec
460 changed files with 12005 additions and 7020 deletions

View File

@@ -1,10 +1,831 @@
// file: kb-lib/src/materializer/token/accounts.rs
// version: 1
// version: 2
//! Migration boundary for legacy crate `kb_materializer_token_accounts`.
//! Stable committed SPL Token mutation and ATA lifecycle projections.
/// Legacy crate name retained for migration and compatibility tracking.
pub const LEGACY_CRATE: &str = "kb_materializer_token_accounts";
const ACCEPTED_FAMILIES: &[crate::MdEventFamily] = &[
crate::MdEventFamily::TokenAccount,
crate::MdEventFamily::TokenMint,
crate::MdEventFamily::TokenBurn,
crate::MdEventFamily::Lifecycle,
];
/// Current porting status.
pub const MIGRATION_STATUS: &str = "source-preserved-pending-port";
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 MtTokenAccountsMaterializer;
impl crate::MtMaterializer for crate::MtTokenAccountsMaterializer {
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: &crate::MdDecodedProtocolEvent) -> bool {
return accepts_event(event);
}
fn materialize_event(
&self,
_event: &crate::MdDecodedProtocolEvent,
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
return std::result::Result::Ok(std::vec::Vec::new());
}
}
impl crate::MtApiEventMaterializer for crate::MtTokenAccountsMaterializer {
fn identity(&self) -> crate::MtApiMaterializerIdentity {
return crate::MtApiMaterializerIdentity {
name: crate::MT_TOKEN_ACCOUNTS_PROCESSOR_NAME.to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
return ACCEPTED_FAMILIES;
}
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
return accepts_event(&observation.event);
}
fn transaction_policy(
&self,
_family: crate::MdEventFamily,
) -> crate::MtApiMaterializationTransactionPolicy {
return crate::MtApiMaterializationTransactionPolicy::SuccessfulCommittedOnly;
}
fn materialize(
&self,
observation: &crate::DcApiDecodedObservation,
) -> crate::MtApiMaterializerExecutionResult {
if !accepts_event(&observation.event) {
return crate::MtApiMaterializerExecutionResult::ignored();
}
if observation.transaction_failed || !observation.observation_committed {
return crate::MtApiMaterializerExecutionResult::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 = crate::MtApiMaterializedOutput {
output_key: format!("token_account_mutation:{operation}:0"),
family: crate::MdMaterializedEventFamily::TokenAccount,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_TOKEN_ACCOUNTS_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::MT_TOKEN_ACCOUNTS_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::MT_TOKEN_ACCOUNTS_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 crate::MtApiMaterializerExecutionResult {
status: crate::MtApiMaterializerOutcomeStatus::Inserted,
outputs: std::vec![output],
diagnostics: std::vec::Vec::new(),
};
}
}
fn accepts_event(event: &crate::MdDecodedProtocolEvent) -> 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_TOKEN2022_PROGRAM_ID
&& event.surface_code.0 == "spl_token2022");
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: &crate::MdDecodedProtocolEvent) -> bool {
return event.program_id.0 == kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID
&& event.surface_code.0 == "spl_associated_token_account"
&& event.event_family == crate::MdEventFamily::Lifecycle
&& ATA_LIFECYCLE_ENTRIES
.iter()
.any(|(entry, _)| return *entry == event.event_name.0);
}
fn materialize_ata(
observation: &crate::DcApiDecodedObservation,
) -> crate::MtApiMaterializerExecutionResult {
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 crate::MtApiMaterializerExecutionResult::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 crate::MtApiMaterializerExecutionResult::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 crate::MtApiMaterializerExecutionResult::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 = crate::MtApiMaterializedOutput {
output_key: format!("ata_lifecycle:{lifecycle_kind}:0"),
family: crate::MdMaterializedEventFamily::TokenAccount,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_TOKEN_ACCOUNTS_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::MT_TOKEN_ACCOUNTS_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::MT_TOKEN_ACCOUNTS_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 crate::MtApiMaterializerExecutionResult {
status: crate::MtApiMaterializerOutcomeStatus::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_TOKEN2022_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_token2022_state_snapshot(
account_key: &str,
slot: u64,
state: &crate::DcToken2022State,
) -> std::result::Result<crate::MtApiMaterializedOutput, 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 {
crate::DcToken2022StateKind::Mint => "mint",
crate::DcToken2022StateKind::Account => "account",
crate::DcToken2022StateKind::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(crate::MtApiMaterializedOutput {
output_key: format!("token2022_state_snapshot:{account_key}:{slot}"),
family: crate::MdMaterializedEventFamily::TokenAccount,
payload_json: serde_json::json!({
"projectionVersion": crate::MT_TOKEN_ACCOUNTS_PROJECTION_VERSION,
"domain": "spl_token2022_account_state",
"projectionSemantics": "authoritative_bounded_account_snapshot",
"idempotenceKey": format!("token2022_state:{account_key}:{slot}"),
"accountKey": account_key,
"slot": slot,
"programId": kb_program_ids::SPL_TOKEN2022_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::MT_TOKEN_ACCOUNTS_PROCESSOR_NAME,
"processorVersion": env!("CARGO_PKG_VERSION"),
"source": "bounded_token2022_state_parser"
}
}),
});
}
#[cfg(test)]
mod tests {
fn observation(
entry: &str,
family: crate::MdEventFamily,
failed: bool,
) -> crate::DcApiDecodedObservation {
return crate::DcApiDecodedObservation {
event_key: format!("token:{entry}:0"),
event: crate::MdDecodedProtocolEvent {
signature: crate::MdSignature("signature".to_string()),
slot: crate::MdSlot(42),
instruction_path: crate::MdInstructionPath("1/0".to_string()),
program_id: crate::MdProgramId(kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string()),
protocol_code: crate::MdProtocolCode("spl_token".to_string()),
surface_code: crate::MdSurfaceCode("spl_token".to_string()),
event_code: crate::MdEventCode(format!("spl_token.{entry}")),
event_name: crate::MdEventName(entry.to_string()),
event_family: family,
source_kind: crate::MdEventSourceKind::InnerInstruction,
confidence: crate::MdDecoderConfidence::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: crate::DcApiDecoderProof {
kind: crate::DcApiDecoderProofKind::Manual,
confidence: crate::MdDecoderConfidence::ManualExact,
evidence: std::vec!["fixture".to_string()],
},
};
}
fn token2022_observation(
entry: &str,
family: crate::MdEventFamily,
failed: bool,
) -> crate::DcApiDecodedObservation {
let mut observation = observation(entry, family, failed);
observation.event.program_id =
crate::MdProgramId(kb_program_ids::SPL_TOKEN2022_PROGRAM_ID.to_string());
observation.event.protocol_code = crate::MdProtocolCode("spl_token2022".to_string());
observation.event.surface_code = crate::MdSurfaceCode("spl_token2022".to_string());
observation.event.event_code = crate::MdEventCode(format!("spl_token2022.{entry}"));
observation.event_key = format!("token2022:{entry}:0");
return observation;
}
fn ata_observation(entry: &str, failed: bool, valid: bool) -> crate::DcApiDecodedObservation {
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_TOKEN2022_PROGRAM_ID,
"kind": "token2022",
"supported": true
},
"associatedTokenAccount": {"expected":"ata111","observed":"ata111","valid":valid},
"fundingAccount": "payer111",
"walletOwner": "wallet111",
"mint": "mint111"
})
};
return crate::DcApiDecodedObservation {
event_key: format!("ata:{entry}:0"),
event: crate::MdDecodedProtocolEvent {
signature: crate::MdSignature("signature".to_string()),
slot: crate::MdSlot(42),
instruction_path: crate::MdInstructionPath("0".to_string()),
program_id: crate::MdProgramId(
kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID.to_string(),
),
protocol_code: crate::MdProtocolCode("spl_associated_token_account".to_string()),
surface_code: crate::MdSurfaceCode("spl_associated_token_account".to_string()),
event_code: crate::MdEventCode(format!("spl_associated_token_account.{entry}")),
event_name: crate::MdEventName(entry.to_string()),
event_family: crate::MdEventFamily::Lifecycle,
source_kind: crate::MdEventSourceKind::Instruction,
confidence: crate::MdDecoderConfidence::ManualExact,
},
payload_json: serde_json::json!({"addresses":addresses}),
transaction_failed: failed,
transaction_error: std::option::Option::None,
observation_committed: !failed,
proof: crate::DcApiDecoderProof {
kind: crate::DcApiDecoderProofKind::Manual,
confidence: crate::MdDecoderConfidence::ManualExact,
evidence: std::vec!["fixture".to_string()],
},
};
}
#[test]
fn committed_checked_transfer_preserves_exact_amount_mint_and_path() {
let observation =
observation("transfer_checked", crate::MdEventFamily::TokenAccount, false);
let result = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::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_token2022_transfer_has_the_same_single_projection_owner() {
let observation =
token2022_observation("transfer_checked", crate::MdEventFamily::TokenAccount, false);
let result = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::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_TOKEN2022_PROGRAM_ID
);
}
#[test]
fn failed_mutation_is_refused() {
let observation = observation("burn", crate::MdEventFamily::TokenBurn, true);
let result = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::Refused);
assert!(result.outputs.is_empty());
}
#[test]
fn batch_parent_admin_and_conversion_events_are_not_duplicated() {
for (entry, family) in [
("batch", crate::MdEventFamily::Audit),
("set_authority", crate::MdEventFamily::Admin),
("amount_to_ui_amount", crate::MdEventFamily::Audit),
] {
let observation = observation(entry, family, false);
let result = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::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_TOKEN2022_PROGRAM_ID),
(
"create_idempotent",
"ata_created_or_reused_idempotently",
"ata111",
kb_program_ids::SPL_TOKEN2022_PROGRAM_ID,
),
(
"recover_nested",
"nested_ata_recovered",
"nestedAta",
kb_program_ids::SPL_TOKEN_PROGRAM_ID,
),
] {
let result = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&ata_observation(entry, false, true),
);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::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 = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&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 = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation,
);
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::Refused);
assert!(result.outputs.is_empty());
}
}
#[test]
fn ata_parent_and_classic_token_cpi_children_own_distinct_facts() {
let parent = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&ata_observation("recover_nested", false, true),
);
let transfer = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation("transfer", crate::MdEventFamily::TokenAccount, false),
);
let close = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation("close_account", crate::MdEventFamily::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 = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&observation,
);
let second = crate::MtApiEventMaterializer::materialize(
&crate::MtTokenAccountsMaterializer,
&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 token2022_state_snapshot_preserves_base_and_ordered_extensions() {
let state = crate::DcToken2022State {
kind: crate::DcToken2022StateKind::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![
crate::DcToken2022TlvEntry {
extension_type: 1,
extension_name: "transfer_fee_config",
value_hex: "11".repeat(108),
value_fields: serde_json::json!({"withheldAmount":"7"}),
},
crate::DcToken2022TlvEntry {
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_token2022_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 token2022_state_snapshot_is_idempotent_and_rejects_missing_identity() {
let state = crate::DcToken2022State {
kind: crate::DcToken2022StateKind::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_token2022_state_snapshot("account111", 7, &state);
let second = crate::materialize_token2022_state_snapshot("account111", 7, &state);
assert_eq!(first, second);
assert!(crate::materialize_token2022_state_snapshot("", 7, &state).is_err());
}
}

View File

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

View File

@@ -1,10 +1,10 @@
// file: kb-lib/src/materializer/token/metadata_risk.rs
// version: 1
// version: 2
//! Migration boundary for legacy crate `kb_materializer_token_metadata_risk`.
/// Legacy crate name retained for migration and compatibility tracking.
pub const LEGACY_CRATE: &str = "kb_materializer_token_metadata_risk";
const LEGACY_CRATE: &str = "kb_materializer_token_metadata_risk";
/// Current porting status.
pub const MIGRATION_STATUS: &str = "source-preserved-pending-port";
const MIGRATION_STATUS: &str = "source-preserved-pending-port";