// file: kb-lib/src/decoder/spl/token/decoder.rs // version: 4 //! Exact classic SPL Token dispatch for the common decode pipeline. const TOKEN_SURFACES: &[crate::DcApiDecoderSurface] = &[crate::DcApiDecoderSurface { program_id: kb_program_ids::SPL_TOKEN_PROGRAM_ID, surface_code: crate::DC_SPL_TOKEN_SURFACE_CODE, priority: 100, }]; const PROGRAM_IDS: &[&str] = &[kb_program_ids::SPL_TOKEN_PROGRAM_ID]; /// Exact decoder for the classic SPL Token program. #[derive(Clone, Debug, Default)] pub struct DcSplTokenDecoder; impl crate::DcApiProtocolDecoder for crate::DcSplTokenDecoder { fn decoder_name(&self) -> &'static str { return "kb-lib.decoder.spl.token"; } fn decoder_version(&self) -> &'static str { return env!("CARGO_PKG_VERSION"); } fn program_ids(&self) -> &'static [&'static str] { return PROGRAM_IDS; } fn supports_observation( &self, observation: &crate::MdProgramObservation, ) -> crate::DcApiDecoderSupport { return if crate::DcApiProtocolDecoder::handles_program_id(self, &observation.program_id) { crate::DcApiDecoderSupport::Yes } else { crate::DcApiDecoderSupport::No }; } fn decode_observation( &self, _observation: &crate::MdProgramObservation, ) -> kb_core::Result> { return std::result::Result::Ok(std::vec::Vec::new()); } } impl crate::DcApiInstructionDecoder for crate::DcSplTokenDecoder { fn identity(&self) -> crate::DcApiDecoderIdentity { return crate::DcApiDecoderIdentity { name: "spl.token".to_string(), version: env!("CARGO_PKG_VERSION").to_string(), }; } fn surfaces(&self) -> &'static [crate::DcApiDecoderSurface] { return TOKEN_SURFACES; } fn coverage(&self) -> std::vec::Vec { return crate::DC_SPL_TOKEN_INSTRUCTION_ENTRIES .iter() .map(|(tag, code, historical)| { return crate::DcApiDecoderCoverageDeclaration { program_id: kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string(), surface_code: std::option::Option::Some( crate::DC_SPL_TOKEN_SURFACE_CODE.to_string(), ), entry_kind: crate::DcApiDecoderCoverageEntryKind::Instruction, entry_code: (*code).to_string(), discriminator_hex: std::option::Option::Some(format!("{tag:02x}")), historical: *historical, }; }) .collect(); } fn recognize( &self, input: &crate::MdCoreInstructionReplayInput, ) -> crate::DcApiDecoderRecognition { if input.program_id != kb_program_ids::SPL_TOKEN_PROGRAM_ID { return crate::DcApiDecoderRecognition::incompatible(); } let tag = crate::decoder_spl_token_payload_tag(input); let entry = tag.and_then(crate::decoder_spl_token_entry_for_tag); return crate::DcApiDecoderRecognition::compatible( entry.is_some(), 100, std::option::Option::Some(crate::DC_SPL_TOKEN_SURFACE_CODE.to_string()), entry.map(|(_, code, _)| return code.to_string()), tag.map(|value| return format!("{value:02x}")), ); } fn decode( &self, input: &crate::MdCoreInstructionReplayInput, ) -> crate::DcApiDecoderExecutionResult { if input.program_id != kb_program_ids::SPL_TOKEN_PROGRAM_ID { return crate::DcApiDecoderExecutionResult::unsupported(std::option::Option::None); } let result = crate::decoder_spl_token_decode(input); if matches!( result.status, crate::DcApiDecoderOutcomeStatus::Failed | crate::DcApiDecoderOutcomeStatus::Unsupported ) { tracing::error!( target: crate::TRACING_TARGET_DECODER_SPL_TOKEN, action = "decode_failure", signature = %input.signature, slot = input.slot, instruction_path = %input.instruction_path, program_id = %input.program_id, processor_name = "spl.token", processor_version = env!("CARGO_PKG_VERSION"), input_key = %input.replay_input_key, payload_hash = ?input.instruction_payload_hash, result_status = ?result.status, diagnostics = ?result.diagnostics, "classic SPL Token instruction was not decoded successfully" ); } tracing::debug!( target: crate::TRACING_TARGET_DECODER_SPL_TOKEN, action = "decode", signature = %input.signature, instruction_path = %input.instruction_path, transaction_failed = input.transaction_failed, result_status = ?result.status, observation_count = result.observations.len(), "classic SPL Token instruction decode completed" ); return result; } } #[cfg(test)] mod tests { use base64::Engine; // rust-rules: trait-import fn input( program_id: &str, payload: &[u8], accounts: serde_json::Value, keys: serde_json::Value, failed: bool, path: &str, ) -> crate::MdCoreInstructionReplayInput { let result = crate::MdCoreInstructionReplayInput::new( format!("signature:{path}"), "signature", 42, path, program_id, failed, if failed { std::option::Option::Some(serde_json::json!({"InstructionError":[0,"Custom"]})) } else { std::option::Option::None }, keys, accounts, std::option::Option::Some(serde_json::json!({ "dataBase64": base64::engine::general_purpose::STANDARD.encode(payload) })), std::option::Option::None, serde_json::json!([]), serde_json::json!([]), serde_json::json!([]), serde_json::json!([]), ); return match result { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => panic!("Token replay input failed: {error}"), }; } fn minimal_wire(tag: u8) -> std::vec::Vec { return match tag { 0 | 20 => { let mut value = std::vec![tag, 9]; value.extend_from_slice(&[1; 32]); value.push(0); value }, 2 | 19 => std::vec![tag, 1], 3 | 4 | 7 | 8 | 23 => { let mut value = std::vec![tag]; value.extend_from_slice(&1_u64.to_le_bytes()); value }, 6 => std::vec![tag, 0, 0], 12 | 13 | 14 | 15 => { let mut value = std::vec![tag]; value.extend_from_slice(&1_u64.to_le_bytes()); value.push(9); value }, 16 | 18 => { let mut value = std::vec![tag]; value.extend_from_slice(&[2; 32]); value }, 24 => std::vec![tag, b'1'], 45 => std::vec![tag, 0], 255 => std::vec![tag, 0, 1, 1], _ => std::vec![tag], }; } fn account(position: usize, signer: bool, writable: bool) -> serde_json::Value { return serde_json::json!({ "position": position, "accountIndex": position, "accountKey": format!("account{position}"), "signer": signer, "writable": writable, "source": "static", }); } #[test] fn exact_support_program_id_and_interface_match() { assert_eq!(spl_token_interface::ID.to_string(), kb_program_ids::SPL_TOKEN_PROGRAM_ID); let decoder = crate::DcSplTokenDecoder; assert_eq!(crate::DcApiInstructionDecoder::surfaces(&decoder).len(), 1); let observation = crate::MdProgramObservation { signature: crate::MdSignature("signature".to_string()), slot: crate::MdSlot(1), instruction_path: crate::MdInstructionPath("0".to_string()), program_id: crate::MdProgramId(kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string()), discriminator_8: std::option::Option::None, data_len: 1, accounts_len: 0, failed: false, }; assert_eq!( crate::DcApiProtocolDecoder::supports_observation(&decoder, &observation), crate::DcApiDecoderSupport::Yes ); } #[test] fn coverage_matrix_and_compiled_entries_are_equal() { let matrix: serde_json::Value = match serde_json::from_str(include_str!( "../../../../../test-fixtures/contract-matrices/SPL_TOKEN_MATRIX.json" )) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => panic!("SPL Token matrix is invalid: {error}"), }; let rows = match matrix.get("instructions").and_then(serde_json::Value::as_array) { std::option::Option::Some(value) => value, std::option::Option::None => panic!("SPL Token matrix has no instructions"), }; let matrix_entries = rows .iter() .map(|row| { return ( row.get("tag").and_then(serde_json::Value::as_u64).unwrap_or(u64::MAX) as u8, row.get("name").and_then(serde_json::Value::as_str).unwrap_or(""), ); }) .collect::>(); let compiled_entries = crate::DC_SPL_TOKEN_INSTRUCTION_ENTRIES .iter() .map(|(tag, code, _)| return (*tag, *code)) .collect::>(); assert_eq!(matrix_entries, compiled_entries); assert_eq!(crate::DcApiInstructionDecoder::coverage(&crate::DcSplTokenDecoder).len(), 28); } #[test] fn cluster_evidence_scopes_recent_instruction_deployment_exactly() { let matrix: serde_json::Value = match serde_json::from_str(include_str!( "../../../../../test-fixtures/contract-matrices/SPL_TOKEN_MATRIX.json" )) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => panic!("SPL Token matrix is invalid: {error}"), }; assert_eq!( matrix["deploymentAudit"]["mainnet"]["status"], "real_corpus_decode_and_materialization_validated" ); assert_eq!(matrix["corpusAudit"]["mainnet"]["invariants"]["uncommittedOutputs"], 0); assert_eq!(matrix["corpusAudit"]["mainnet"]["invariants"]["secondReplaySelected"], 0); assert_eq!(matrix["corpusAudit"]["devnet"]["recentInstructionProbe"]["submission"], false); assert_eq!( matrix["corpusAudit"]["devnet"]["recentInstructionProbe"]["batch"]["success"], true ); assert_eq!( matrix["corpusAudit"]["devnet"]["recentInstructionProbe"]["batch"]["computeUnits"], 270 ); assert_eq!( matrix["corpusAudit"]["devnet"]["recentInstructionProbe"]["unwrapLamports"]["success"], true ); assert_eq!( matrix["corpusAudit"]["devnet"]["recentInstructionProbe"]["unwrapLamports"]["computeUnits"], 140 ); let instructions = match matrix.get("instructions").and_then(serde_json::Value::as_array) { std::option::Option::Some(value) => value, std::option::Option::None => panic!("SPL Token matrix has no instructions"), }; for recent_name in ["unwrap_lamports", "batch"] { let recent = match instructions.iter().find(|row| { return row.get("name").and_then(serde_json::Value::as_str) == std::option::Option::Some(recent_name); }) { std::option::Option::Some(value) => value, std::option::Option::None => { panic!("recent SPL Token instruction {recent_name} is absent") }, }; assert_eq!(recent["executorSupport"]["constructibility"], "official_builder_proven"); assert_eq!( recent["executorSupport"]["clusterDeployment"], "devnet_simulation_succeeded_2026-07-16" ); assert_eq!(recent["clusterStatus"]["localnet"], "not_tested"); assert_eq!(recent["clusterStatus"]["devnet"], "simulation_succeeded_2026-07-16"); assert_eq!(recent["clusterStatus"]["mainnet"], "not_tested"); assert_eq!(recent["realSignatures"].as_array().map(std::vec::Vec::len), Some(0)); } } #[test] fn every_published_tag_decodes_and_matches_official_unpack() { for (tag, code, _) in crate::DC_SPL_TOKEN_INSTRUCTION_ENTRIES { let wire = minimal_wire(*tag); let official = spl_token_interface::instruction::TokenInstruction::unpack(&wire); assert!(official.is_ok(), "official unpack rejected tag {tag}"); let input = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, wire.as_slice(), serde_json::json!([]), serde_json::json!([]), false, "0", ); let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &input); assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded); assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some(*code)); } } #[test] fn failed_transfer_is_an_exact_uncommitted_inner_intent_without_invented_mint() { let mut wire = std::vec![3]; wire.extend_from_slice(&u64::MAX.to_le_bytes()); let accounts = serde_json::json!([ {"position":0,"accountIndex":0,"accountKey":"source"}, {"position":1,"accountIndex":1,"accountKey":"destination"}, {"position":2,"accountIndex":2,"accountKey":"authority"} ]); let keys = serde_json::json!([ {"accountIndex":0,"accountKey":"source","signer":false,"writable":true,"source":"static"}, {"accountIndex":1,"accountKey":"destination","signer":false,"writable":true,"source":"static"}, {"accountIndex":2,"accountKey":"authority","signer":true,"writable":false,"source":"static"} ]); let input = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, wire.as_slice(), accounts, keys, true, "2/1", ); let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &input); assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded); assert!(!result.observations[0].observation_committed); assert_eq!( result.observations[0].payload_json["parameters"]["amountRaw"], u64::MAX.to_string() ); assert_eq!(result.observations[0].payload_json["inference"]["mintInvented"], false); assert_eq!( result.observations[0].event.source_kind, crate::MdEventSourceKind::InnerInstruction ); } #[test] fn suffix_unknown_empty_truncated_and_invalid_utf8_are_bounded() { let mut transfer = minimal_wire(3); transfer.extend_from_slice(&[0xaa, 0xbb]); let suffix = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, transfer.as_slice(), serde_json::json!([]), serde_json::json!([]), false, "0", ); let suffix_result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &suffix); assert_eq!(suffix_result.status, crate::DcApiDecoderOutcomeStatus::Decoded); assert_eq!(suffix_result.observations[0].payload_json["wire"]["suffixLengthBytes"], 2); for wire in [std::vec::Vec::new(), std::vec![3, 1], std::vec![24, 0xff], std::vec![255]] { let input = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, wire.as_slice(), serde_json::json!([]), serde_json::json!([]), false, "0", ); let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &input); assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Failed); assert!(result.observations.is_empty()); } let unknown = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, &[44], serde_json::json!([]), serde_json::json!([]), false, "0", ); let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &unknown); assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Unsupported); assert!(!result.diagnostics.is_empty()); } #[test] fn batch_preserves_order_slices_paths_and_rejects_nested_batch() { let mut batch = std::vec![255, 0, 9, 3]; batch.extend_from_slice(&1_u64.to_le_bytes()); batch.extend_from_slice(&[0, 1, 17]); let cinput = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, batch.as_slice(), serde_json::json!([]), serde_json::json!([]), false, "4/2", ); let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &cinput); assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded); assert_eq!(result.observations.len(), 3); assert_eq!(result.observations[1].event.instruction_path.0, "4/2/batch/0"); assert_eq!(result.observations[2].event.instruction_path.0, "4/2/batch/1"); assert_eq!(result.observations[0].payload_json["parameters"]["subInstructionCount"], 2); let nested = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, &[255, 0, 1, 255], serde_json::json!([]), serde_json::json!([]), false, "0", ); let nested_result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &nested); assert_eq!(nested_result.status, crate::DcApiDecoderOutcomeStatus::Failed); } #[test] fn authority_forms_and_multisig_threshold_diagnostics_are_explicit() { let wire = minimal_wire(3); let simple_accounts = serde_json::json!([ {"position":0,"accountIndex":0,"accountKey":"account0"}, {"position":1,"accountIndex":1,"accountKey":"account1"}, {"position":2,"accountIndex":2,"accountKey":"account2"} ]); let simple_keys = serde_json::json!([ account(0, false, true), account(1, false, true), account(2, true, false) ]); let simple = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, wire.as_slice(), simple_accounts.clone(), simple_keys, false, "0", ); let simple_result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &simple); assert_eq!(simple_result.observations[0].payload_json["authority"]["form"], "single"); let mut multisig_accounts = simple_accounts.as_array().cloned().unwrap_or_default(); multisig_accounts .push(serde_json::json!({"position":3,"accountIndex":3,"accountKey":"account3"})); let multisig_keys = serde_json::json!([ account(0, false, true), account(1, false, true), account(2, false, false), account(3, true, false) ]); let multisig = input( kb_program_ids::SPL_TOKEN_PROGRAM_ID, wire.as_slice(), serde_json::Value::Array(multisig_accounts), multisig_keys, false, "0", ); let multisig_result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &multisig); assert_eq!(multisig_result.observations[0].payload_json["authority"]["form"], "multisig"); assert_eq!( multisig_result.observations[0].payload_json["authority"]["statefulMultisigValidation"], "requires_multisig_account_snapshot" ); } }