// file: kb_pipeline/src/solana_ata_stateful.rs // version: 3 //! Stateful Localnet and Devnet readiness checks for ATA operations. const BASE_MINT_LEN: usize = 82; const BASE_TOKEN_ACCOUNT_LEN: usize = 165; const MAX_TOKEN_2022_ACCOUNT_BYTES: usize = 16_384; macro_rules! result_value { ($expression:expr) => { match $expression { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), } }; } /// ATA stateful readiness outcome. #[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] pub enum SplAssociatedTokenAccountStatefulReadinessStatus { /// Every stateful check passed. Ready, /// At least one stateful check failed. Blocked, } /// One machine-readable ATA stateful check. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SplAssociatedTokenAccountStatefulCheck { /// Stable diagnostic code. pub code: std::string::String, /// Whether the check passed. pub passed: bool, /// Operator-readable explanation. pub message: std::string::String, } /// One contextual ATA stateful fact. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SplAssociatedTokenAccountStatefulFact { /// Stable fact key. pub key: std::string::String, /// Exact string representation. pub value: std::string::String, } /// Complete request for one ATA stateful readiness inspection. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SplAssociatedTokenAccountStatefulReadinessRequest { /// HTTP endpoint role used for every state read. pub query_role: std::string::String, /// Expected Localnet or Devnet cluster. pub cluster: kb_execution_api::ExecutionCluster, /// Typed simulation-first ATA intent. pub intent: kb_executor_spl_associated_token_account::SplAssociatedTokenAccountExecutionIntent, /// Signer public keys currently available to the caller. pub available_signers: std::vec::Vec, } /// Complete ATA stateful readiness report. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SplAssociatedTokenAccountStatefulReadinessReport { /// Expected cluster. pub cluster: kb_execution_api::ExecutionCluster, /// Stable operation code. pub operation_code: std::string::String, /// Aggregate readiness status. pub status: crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus, /// Highest contextual slot observed. pub context_slot: std::option::Option, /// Ordered checks. pub checks: std::vec::Vec, /// Ordered facts. pub facts: std::vec::Vec, } /// Stateful ATA invariants observed after a confirmed execution. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SplAssociatedTokenAccountPostExecutionReport { /// Expected Localnet or Devnet cluster. pub cluster: kb_execution_api::ExecutionCluster, /// Stable operation code. pub operation_code: std::string::String, /// Aggregate postcondition status. pub status: crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus, /// Highest contextual slot observed. pub context_slot: std::option::Option, /// Ordered state checks. pub checks: std::vec::Vec, /// Ordered derived-address facts. pub facts: std::vec::Vec, } type AccountCache = std::collections::BTreeMap>; /// Inspects Localnet or Devnet ATA state required before simulation. pub async fn inspect_spl_associated_token_account_stateful_readiness( pool: &kb_rpc::HttpEndpointPool, request: &crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessRequest, ) -> kb_core::Result { if request.query_role.trim().is_empty() { return std::result::Result::Err(kb_core::Error::config( "ATA stateful readiness query_role must not be empty", )); } match crate::solana_ata_stateful::validate_cluster_kind(request.cluster) { std::result::Result::Ok(()) => {}, std::result::Result::Err(error) => return std::result::Result::Err(error), } let genesis = match pool.get_genesis_hash_for_role(request.query_role.as_str()).await { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; match crate::solana_ata_stateful::validate_genesis(request.cluster, &genesis) { std::result::Result::Ok(()) => {}, std::result::Result::Err(error) => return std::result::Result::Err(error), } let plan = match kb_execution_api::TypedInstructionExecutor::build_prepared_plan( &kb_executor_spl_associated_token_account::SplAssociatedTokenAccountExecutor, &request.intent, ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let addresses = match crate::solana_ata_stateful::operation_addresses(&request.intent.operation) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let config = match kb_rpc::GetAccountInfoConfig::confirmed_with_data( crate::solana_ata_stateful::MAX_TOKEN_2022_ACCOUNT_BYTES, ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let mut cache = crate::solana_ata_stateful::AccountCache::new(); let mut context_slot: std::option::Option = std::option::Option::None; for address in &addresses { let result = match pool .get_account_info_for_role(request.query_role.as_str(), address, &config) .await { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; context_slot = std::option::Option::Some(match context_slot { std::option::Option::Some(slot) => slot.max(result.context.slot), std::option::Option::None => result.context.slot, }); cache.insert(address.0.clone(), result.account); } let rent = match pool .get_minimum_balance_for_rent_exemption_for_role( request.query_role.as_str(), crate::solana_ata_stateful::BASE_TOKEN_ACCOUNT_LEN as u64, &kb_rpc::GetMinimumBalanceForRentExemptionConfig::confirmed(), ) .await { std::result::Result::Ok(value) => value.minimum_balance_lamports, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let balance_config = kb_rpc::GetBalanceConfig::confirmed(); let payer_balance = match pool .get_balance_for_role( request.query_role.as_str(), &request.intent.fee_payer, &balance_config, ) .await { std::result::Result::Ok(value) => value.lamports, std::result::Result::Err(error) => return std::result::Result::Err(error), }; return crate::solana_ata_stateful::evaluate( request, &plan, &genesis.genesis_hash, context_slot, &cache, rent, payer_balance, ); } /// Verifies final ATA account relationships after a confirmed execution. pub async fn inspect_spl_associated_token_account_post_execution( pool: &kb_rpc::HttpEndpointPool, query_role: &str, cluster: kb_execution_api::ExecutionCluster, operation: &kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation, ) -> kb_core::Result { if query_role.trim().is_empty() { return std::result::Result::Err(kb_core::Error::config( "ATA post-execution query role must not be empty", )); } if let std::result::Result::Err(error) = crate::solana_ata_stateful::validate_cluster_kind(cluster) { return std::result::Result::Err(error); } let genesis = match pool.get_genesis_hash_for_role(query_role).await { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; if let std::result::Result::Err(error) = crate::solana_ata_stateful::validate_genesis(cluster, &genesis) { return std::result::Result::Err(error); } let addresses = match crate::solana_ata_stateful::operation_addresses(operation) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let config = match kb_rpc::GetAccountInfoConfig::confirmed_with_data( crate::solana_ata_stateful::MAX_TOKEN_2022_ACCOUNT_BYTES, ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let mut cache = crate::solana_ata_stateful::AccountCache::new(); let mut context_slot: std::option::Option = std::option::Option::None; for address in &addresses { let result = match pool.get_account_info_for_role(query_role, address, &config).await { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; context_slot = std::option::Option::Some(match context_slot { std::option::Option::Some(slot) => slot.max(result.context.slot), std::option::Option::None => result.context.slot, }); cache.insert(address.0.clone(), result.account); } return crate::solana_ata_stateful::evaluate_post_execution( cluster, operation, context_slot, &cache, ); } fn validate_cluster_kind(cluster: kb_execution_api::ExecutionCluster) -> kb_core::Result<()> { return match cluster { kb_execution_api::ExecutionCluster::Localnet | kb_execution_api::ExecutionCluster::Devnet => std::result::Result::Ok(()), kb_execution_api::ExecutionCluster::Testnet | kb_execution_api::ExecutionCluster::Mainnet => { std::result::Result::Err(kb_core::Error::new( "spl_ata_stateful_cluster_unsupported", "ATA stateful readiness is restricted to Localnet and Devnet", )) }, }; } fn validate_genesis( expected: kb_execution_api::ExecutionCluster, genesis: &kb_rpc::GenesisHashResult, ) -> kb_core::Result<()> { return match expected { kb_execution_api::ExecutionCluster::Devnet if genesis.classified_cluster == std::option::Option::Some(kb_execution_api::ExecutionCluster::Devnet) => { std::result::Result::Ok(()) }, kb_execution_api::ExecutionCluster::Localnet if genesis.classified_cluster.is_none() => { std::result::Result::Ok(()) }, kb_execution_api::ExecutionCluster::Devnet => { std::result::Result::Err(kb_core::Error::new( "spl_ata_stateful_devnet_genesis_mismatch", "ATA Devnet readiness requires the official Devnet genesis hash", )) }, kb_execution_api::ExecutionCluster::Localnet => { std::result::Result::Err(kb_core::Error::new( "spl_ata_stateful_localnet_public_cluster", "ATA Localnet readiness refuses endpoints classified as a public cluster", )) }, kb_execution_api::ExecutionCluster::Testnet | kb_execution_api::ExecutionCluster::Mainnet => { crate::solana_ata_stateful::validate_cluster_kind(expected) }, }; } fn operation_addresses( operation: &kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation, ) -> kb_core::Result> { let mut values = std::vec::Vec::new(); match operation { kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::Create { wallet_owner, mint, token_program, } | kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::CreateIdempotent { wallet_owner, mint, token_program, } => { values.push(mint.clone()); values.push(result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, mint, token_program.program_id(), ))); }, kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::RecoverNested { wallet_owner, owner_mint, nested_mint, token_program, } => { let owner_ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, owner_mint, token_program.program_id(), )); let nested_ata = result_value!(crate::solana_ata_stateful::derive_ata( &owner_ata, nested_mint, token_program.program_id(), )); let destination_ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, nested_mint, token_program.program_id(), )); values.extend([ owner_mint.clone(), nested_mint.clone(), owner_ata, nested_ata, destination_ata, ]); }, } values.sort_by(|left, right| return left.0.cmp(&right.0)); values.dedup(); return std::result::Result::Ok(values); } fn derive_ata( wallet: &kb_model::Pubkey, mint: &kb_model::Pubkey, token_program: &str, ) -> kb_core::Result { let wallet: solana_pubkey::Pubkey = match wallet.0.parse() { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return std::result::Result::Err(kb_core::Error::new( "spl_ata_stateful_wallet_invalid", error.to_string(), )); }, }; let mint: solana_pubkey::Pubkey = match mint.0.parse() { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return std::result::Result::Err(kb_core::Error::new( "spl_ata_stateful_mint_invalid", error.to_string(), )); }, }; let token_program: solana_pubkey::Pubkey = match token_program.parse() { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return std::result::Result::Err(kb_core::Error::new( "spl_ata_stateful_token_program_invalid", error.to_string(), )); }, }; let derived = spl_associated_token_account_interface::address::get_associated_token_address_with_program_id( &wallet, &mint, &token_program, ); return std::result::Result::Ok(kb_model::Pubkey(derived.to_string())); } fn evaluate( request: &crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessRequest, plan: &kb_execution_api::PreparedExecutionPlan, genesis_hash: &str, context_slot: std::option::Option, cache: &crate::solana_ata_stateful::AccountCache, base_rent_lamports: u64, payer_balance_lamports: u64, ) -> kb_core::Result { let mut report = crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport { cluster: request.cluster, operation_code: request.intent.operation.operation_code().to_string(), status: crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus::Ready, context_slot, checks: std::vec::Vec::new(), facts: std::vec![ crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulFact { key: "genesis_hash".to_string(), value: genesis_hash.to_string(), }, crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulFact { key: "base_token_account_rent_lamports".to_string(), value: base_rent_lamports.to_string(), }, ], }; crate::solana_ata_stateful::push_check( &mut report, "ata_program_id", plan.instructions.len() == 1 && plan.instructions[0].program_id.0 == kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID, "plan must contain exactly one instruction for the canonical ATA Program", ); crate::solana_ata_stateful::push_check( &mut report, "simulation_required", plan.policy.simulation == kb_execution_api::ExecutionSimulationPolicy::Required, "ATA plan must require simulation", ); for signer in &plan.required_signers { crate::solana_ata_stateful::push_check( &mut report, "required_signer_available", request.available_signers.contains(&signer.pubkey), format!("required {} signer {} must be available", signer.role, signer.pubkey.0), ); } let max_fee = match plan.policy.cost_limit.max_fee_lamports { std::option::Option::Some(value) => value, std::option::Option::None => 0, }; let total_ceiling = match plan.requested_spend_lamports.checked_add(max_fee) { std::option::Option::Some(value) => value, std::option::Option::None => u64::MAX, }; crate::solana_ata_stateful::push_check( &mut report, "payer_balance_covers_ceiling", payer_balance_lamports >= total_ceiling, format!("payer balance must cover rent-plus-fee ceiling {total_ceiling}"), ); let operation = &request.intent.operation; match operation { kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::Create { wallet_owner, mint, token_program, } => { crate::solana_ata_stateful::check_mint(&mut report, cache, mint, token_program.program_id()); let ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, mint, token_program.program_id(), )); crate::solana_ata_stateful::push_fact(&mut report, "derived_ata", ata.0.clone()); crate::solana_ata_stateful::check_creation_plan_accounts( &mut report, plan, &ata, token_program.program_id(), ); crate::solana_ata_stateful::push_check( &mut report, "create_ata_absent", cache.get(ata.0.as_str()).is_some_and(|value| return value.is_none()), "strict Create requires the canonical ATA to be absent", ); crate::solana_ata_stateful::push_check( &mut report, "rent_ceiling_covers_base_account", plan.requested_spend_lamports >= base_rent_lamports, "creation rent ceiling must cover at least the base Token account rent", ); }, kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::CreateIdempotent { wallet_owner, mint, token_program, } => { crate::solana_ata_stateful::check_mint(&mut report, cache, mint, token_program.program_id()); let ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, mint, token_program.program_id(), )); crate::solana_ata_stateful::push_fact(&mut report, "derived_ata", ata.0.clone()); crate::solana_ata_stateful::check_creation_plan_accounts( &mut report, plan, &ata, token_program.program_id(), ); if let std::option::Option::Some(std::option::Option::Some(account)) = cache.get(ata.0.as_str()) { crate::solana_ata_stateful::check_token_account( &mut report, account, token_program.program_id(), mint, wallet_owner, "idempotent_existing_ata", ); } else { crate::solana_ata_stateful::push_check( &mut report, "idempotent_absent_or_compatible", cache.contains_key(ata.0.as_str()), "idempotent ATA must be confirmed absent or validated as compatible", ); crate::solana_ata_stateful::push_check( &mut report, "rent_ceiling_covers_base_account", plan.requested_spend_lamports >= base_rent_lamports, "absent idempotent ATA requires a ceiling covering base account rent", ); } }, kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::RecoverNested { wallet_owner, owner_mint, nested_mint, token_program, } => { crate::solana_ata_stateful::check_mint(&mut report, cache, owner_mint, token_program.program_id()); crate::solana_ata_stateful::check_mint(&mut report, cache, nested_mint, token_program.program_id()); let owner_ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, owner_mint, token_program.program_id(), )); let nested_ata = result_value!(crate::solana_ata_stateful::derive_ata( &owner_ata, nested_mint, token_program.program_id(), )); let destination_ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, nested_mint, token_program.program_id(), )); for (key, value) in [ ("derived_owner_ata", &owner_ata), ("derived_nested_ata", &nested_ata), ("derived_destination_ata", &destination_ata), ] { crate::solana_ata_stateful::push_fact(&mut report, key, value.0.clone()); } let accounts_exact = match plan.instructions.first() { std::option::Option::Some(instruction) => { instruction.accounts.len() == 7 && instruction.accounts[0].pubkey == nested_ata && instruction.accounts[2].pubkey == destination_ata && instruction.accounts[3].pubkey == owner_ata && instruction.accounts[6].pubkey.0 == token_program.program_id() }, std::option::Option::None => false, }; crate::solana_ata_stateful::push_check( &mut report, "recover_plan_accounts_exact", accounts_exact, "RecoverNested plan must retain all three derived ATA addresses and selected Token Program in official positions", ); crate::solana_ata_stateful::check_cached_token_account(&mut report, cache, &owner_ata, token_program.program_id(), owner_mint, wallet_owner, "owner_ata"); crate::solana_ata_stateful::check_cached_token_account(&mut report, cache, &nested_ata, token_program.program_id(), nested_mint, &owner_ata, "nested_ata"); crate::solana_ata_stateful::check_cached_token_account(&mut report, cache, &destination_ata, token_program.program_id(), nested_mint, wallet_owner, "destination_ata"); crate::solana_ata_stateful::push_check( &mut report, "recovery_zero_rent_spend", plan.requested_spend_lamports == 0, "RecoverNested must not reserve rent spending", ); }, } report.status = if report.checks.iter().all(|check| return check.passed) { crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus::Ready } else { crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus::Blocked }; return std::result::Result::Ok(report); } fn evaluate_post_execution( cluster: kb_execution_api::ExecutionCluster, operation: &kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation, context_slot: std::option::Option, cache: &crate::solana_ata_stateful::AccountCache, ) -> kb_core::Result { let mut report = crate::solana_ata_stateful::SplAssociatedTokenAccountPostExecutionReport { cluster, operation_code: operation.operation_code().to_string(), status: crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus::Ready, context_slot, checks: std::vec::Vec::new(), facts: std::vec::Vec::new(), }; match operation { kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::Create { wallet_owner, mint, token_program, } | kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::CreateIdempotent { wallet_owner, mint, token_program, } => { let ata = match crate::solana_ata_stateful::derive_ata( wallet_owner, mint, token_program.program_id(), ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; crate::solana_ata_stateful::push_post_fact(&mut report, "derived_ata", ata.0.clone()); crate::solana_ata_stateful::check_post_cached_token_account( &mut report, cache, &ata, token_program.program_id(), mint, wallet_owner, "post_execution_ata", ); }, kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::RecoverNested { wallet_owner, owner_mint, nested_mint, token_program, } => { let owner_ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, owner_mint, token_program.program_id(), )); let nested_ata = result_value!(crate::solana_ata_stateful::derive_ata( &owner_ata, nested_mint, token_program.program_id(), )); let destination_ata = result_value!(crate::solana_ata_stateful::derive_ata( wallet_owner, nested_mint, token_program.program_id(), )); for (key, value) in [ ("derived_owner_ata", &owner_ata), ("derived_nested_ata", &nested_ata), ("derived_destination_ata", &destination_ata), ] { crate::solana_ata_stateful::push_post_fact(&mut report, key, value.0.clone()); } crate::solana_ata_stateful::check_post_cached_token_account( &mut report, cache, &owner_ata, token_program.program_id(), owner_mint, wallet_owner, "post_execution_owner_ata", ); crate::solana_ata_stateful::push_post_check( &mut report, "post_execution_nested_ata_closed", cache .get(nested_ata.0.as_str()) .is_some_and(|account| return account.is_none()), "confirmed RecoverNested must leave the nested ATA closed", ); crate::solana_ata_stateful::check_post_cached_token_account( &mut report, cache, &destination_ata, token_program.program_id(), nested_mint, wallet_owner, "post_execution_destination_ata", ); }, } report.status = if report.checks.iter().all(|check| return check.passed) { crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus::Ready } else { crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessStatus::Blocked }; return std::result::Result::Ok(report); } fn check_post_cached_token_account( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountPostExecutionReport, cache: &crate::solana_ata_stateful::AccountCache, address: &kb_model::Pubkey, token_program: &str, expected_mint: &kb_model::Pubkey, expected_owner: &kb_model::Pubkey, role: &str, ) { let account = cache.get(address.0.as_str()).and_then(|value| return value.as_ref()); crate::solana_ata_stateful::push_post_check( report, format!("{role}_exists"), account.is_some(), format!("{role} {} must exist after confirmed execution", address.0), ); if let std::option::Option::Some(account) = account { crate::solana_ata_stateful::push_post_check( report, format!("{role}_token_program_owner"), account.owner.0 == token_program, format!("{role} must be owned by the selected Token Program"), ); let layout_valid = account.data.len() >= crate::solana_ata_stateful::BASE_TOKEN_ACCOUNT_LEN; crate::solana_ata_stateful::push_post_check( report, format!("{role}_base_layout"), layout_valid, format!("{role} must expose the complete base Token Account layout"), ); if layout_valid { let mint = bs58::encode(&account.data[0..32]).into_string(); let owner = bs58::encode(&account.data[32..64]).into_string(); crate::solana_ata_stateful::push_post_check( report, format!("{role}_mint"), mint == expected_mint.0, format!("{role} mint must match {}", expected_mint.0), ); crate::solana_ata_stateful::push_post_check( report, format!("{role}_wallet_owner"), owner == expected_owner.0, format!("{role} owner must match {}", expected_owner.0), ); crate::solana_ata_stateful::push_post_check( report, format!("{role}_initialized"), matches!(account.data[108], 1 | 2), format!("{role} must be initialized or frozen"), ); } } } fn push_post_check( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountPostExecutionReport, code: impl std::convert::Into, passed: bool, message: impl std::convert::Into, ) { report .checks .push(crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulCheck { code: code.into(), passed, message: message.into(), }); } fn push_post_fact( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountPostExecutionReport, key: impl std::convert::Into, value: impl std::convert::Into, ) { report .facts .push(crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulFact { key: key.into(), value: value.into(), }); } fn check_creation_plan_accounts( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport, plan: &kb_execution_api::PreparedExecutionPlan, derived_ata: &kb_model::Pubkey, token_program: &str, ) { let accounts_exact = match plan.instructions.first() { std::option::Option::Some(instruction) => { instruction.accounts.len() == 6 && instruction.accounts[1].pubkey == derived_ata.clone() && instruction.accounts[4].pubkey.0 == kb_program_ids::SYSTEM_PROGRAM_ID && instruction.accounts[5].pubkey.0 == token_program }, std::option::Option::None => false, }; crate::solana_ata_stateful::push_check( report, "creation_plan_accounts_exact", accounts_exact, "creation plan must retain derived ATA, System Program and selected Token Program in official positions", ); } fn check_mint( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport, cache: &crate::solana_ata_stateful::AccountCache, mint: &kb_model::Pubkey, token_program: &str, ) { let account = cache.get(mint.0.as_str()).and_then(|value| return value.as_ref()); crate::solana_ata_stateful::push_check( report, "mint_exists", account.is_some(), format!("mint {} must exist", mint.0), ); if let std::option::Option::Some(account) = account { crate::solana_ata_stateful::push_check( report, "mint_token_program_owner", account.owner.0 == token_program, format!("mint {} must be owned by selected Token Program", mint.0), ); crate::solana_ata_stateful::push_check( report, "mint_base_layout", account.data.len() >= crate::solana_ata_stateful::BASE_MINT_LEN, format!("mint {} must expose the complete base Mint layout", mint.0), ); crate::solana_ata_stateful::push_check( report, "mint_initialized", account.data.get(45) == std::option::Option::Some(&1), format!("mint {} must be initialized", mint.0), ); } } fn check_cached_token_account( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport, cache: &crate::solana_ata_stateful::AccountCache, address: &kb_model::Pubkey, token_program: &str, expected_mint: &kb_model::Pubkey, expected_owner: &kb_model::Pubkey, role: &str, ) { let account = cache.get(address.0.as_str()).and_then(|value| return value.as_ref()); crate::solana_ata_stateful::push_check( report, format!("{role}_exists"), account.is_some(), format!("{role} {} must exist", address.0), ); if let std::option::Option::Some(account) = account { crate::solana_ata_stateful::check_token_account( report, account, token_program, expected_mint, expected_owner, role, ); } } fn check_token_account( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport, account: &kb_rpc::AccountInfoValue, token_program: &str, expected_mint: &kb_model::Pubkey, expected_owner: &kb_model::Pubkey, role: &str, ) { crate::solana_ata_stateful::push_check( report, format!("{role}_token_program_owner"), account.owner.0 == token_program, format!("{role} must be owned by selected Token Program"), ); let layout_valid = account.data.len() >= crate::solana_ata_stateful::BASE_TOKEN_ACCOUNT_LEN; crate::solana_ata_stateful::push_check( report, format!("{role}_base_layout"), layout_valid, format!("{role} must expose the complete base Token Account layout"), ); if layout_valid { let mint = bs58::encode(&account.data[0..32]).into_string(); let owner = bs58::encode(&account.data[32..64]).into_string(); crate::solana_ata_stateful::push_check( report, format!("{role}_mint"), mint == expected_mint.0, format!("{role} mint must match {}", expected_mint.0), ); crate::solana_ata_stateful::push_check( report, format!("{role}_wallet_owner"), owner == expected_owner.0, format!("{role} owner must match {}", expected_owner.0), ); crate::solana_ata_stateful::push_check( report, format!("{role}_initialized"), matches!(account.data[108], 1 | 2), format!("{role} must be initialized or frozen"), ); } } fn push_check( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport, code: impl std::convert::Into, passed: bool, message: impl std::convert::Into, ) { report .checks .push(crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulCheck { code: code.into(), passed, message: message.into(), }); } fn push_fact( report: &mut crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessReport, key: impl std::convert::Into, value: impl std::convert::Into, ) { report .facts .push(crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulFact { key: key.into(), value: value.into(), }); } #[cfg(test)] mod tests { fn pubkey(value: &str) -> kb_model::Pubkey { return kb_model::Pubkey(value.to_string()); } fn policy( rent: u64, signers: std::vec::Vec, ) -> kb_execution_api::ExecutionPolicy { return kb_execution_api::ExecutionPolicy { cost_limit: kb_execution_api::ExecutionCostLimit { max_spend_lamports: std::option::Option::Some(rent), max_fee_lamports: std::option::Option::Some(10_000), max_compute_unit_price_micro_lamports: std::option::Option::None, }, authorized_signers: signers, post_execution_validation: kb_execution_api::PostExecutionValidationPolicy { canonical_insert_required: true, core_extraction_required: true, decode_replay_required: true, materialization_required: true, }, ..kb_execution_api::ExecutionPolicy::default() }; } fn request( operation: kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation, rent: u64, ) -> crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessRequest { let fee_payer = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::SYSTEM_PROGRAM_ID); let wallet = match &operation { kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::Create { wallet_owner, .. } | kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::CreateIdempotent { wallet_owner, .. } | kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::RecoverNested { wallet_owner, .. } => wallet_owner.clone(), }; let mut signers = std::vec![fee_payer.clone()]; if !signers.contains(&wallet) { signers.push(wallet); } return crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessRequest { query_role: "query".to_string(), cluster: kb_execution_api::ExecutionCluster::Devnet, intent: kb_executor_spl_associated_token_account::SplAssociatedTokenAccountExecutionIntent { intent_id: "ata-stateful-1".to_string(), fee_payer, max_rent_lamports: rent, policy: crate::solana_ata_stateful::tests::policy(rent, signers.clone()), operation, }, available_signers: signers, }; } fn mint_account(token_program: &str) -> kb_rpc::AccountInfoValue { let mut data = std::vec![0; crate::solana_ata_stateful::BASE_MINT_LEN]; data[45] = 1; return kb_rpc::AccountInfoValue { lamports: 1, owner: kb_model::ProgramId(token_program.to_string()), executable: false, rent_epoch: 0, space: data.len() as u64, data, }; } fn token_account( token_program: &str, mint: &kb_model::Pubkey, owner: &kb_model::Pubkey, ) -> kb_rpc::AccountInfoValue { let mut data = std::vec![0; crate::solana_ata_stateful::BASE_TOKEN_ACCOUNT_LEN]; let mint_bytes = bs58::decode(&mint.0) .into_vec() .unwrap_or_else(|error| panic!("mint fixture decode failed: {error}")); let owner_bytes = bs58::decode(&owner.0) .into_vec() .unwrap_or_else(|error| panic!("owner fixture decode failed: {error}")); data[0..32].copy_from_slice(&mint_bytes); data[32..64].copy_from_slice(&owner_bytes); data[108] = 1; return kb_rpc::AccountInfoValue { lamports: 1, owner: kb_model::ProgramId(token_program.to_string()), executable: false, rent_epoch: 0, space: data.len() as u64, data, }; } fn plan( request: &crate::solana_ata_stateful::SplAssociatedTokenAccountStatefulReadinessRequest, ) -> kb_execution_api::PreparedExecutionPlan { return kb_execution_api::TypedInstructionExecutor::build_prepared_plan( &kb_executor_spl_associated_token_account::SplAssociatedTokenAccountExecutor, &request.intent, ) .unwrap_or_else(|error| panic!("ATA test plan failed: {error}")); } #[test] fn absent_classic_create_is_ready_with_exact_derived_address_and_rent_ceiling() { let wallet = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::STAKE_PROGRAM_ID); let mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::VOTE_PROGRAM_ID); let request = crate::solana_ata_stateful::tests::request( kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::Create { wallet_owner: wallet.clone(), mint: mint.clone(), token_program: kb_executor_spl_associated_token_account::SplAssociatedTokenProgram::Classic, }, 2_100_000, ); let ata = crate::solana_ata_stateful::derive_ata( &wallet, &mint, kb_program_ids::SPL_TOKEN_PROGRAM_ID, ) .unwrap_or_else(|error| panic!("ATA derivation failed: {error}")); let mut cache = crate::solana_ata_stateful::AccountCache::new(); cache.insert( mint.0.clone(), std::option::Option::Some(crate::solana_ata_stateful::tests::mint_account( kb_program_ids::SPL_TOKEN_PROGRAM_ID, )), ); cache.insert(ata.0, std::option::Option::None); let report = crate::solana_ata_stateful::evaluate( &request, &crate::solana_ata_stateful::tests::plan(&request), "devnet", std::option::Option::Some(1), &cache, 2_000_000, 3_000_000, ) .unwrap_or_else(|error| panic!("ATA readiness failed: {error}")); assert_eq!(report.status, crate::SplAssociatedTokenAccountStatefulReadinessStatus::Ready); } #[test] fn idempotent_existing_account_conflict_is_blocked() { let wallet = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::STAKE_PROGRAM_ID); let mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::VOTE_PROGRAM_ID); let request = crate::solana_ata_stateful::tests::request( kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::CreateIdempotent { wallet_owner: wallet.clone(), mint: mint.clone(), token_program: kb_executor_spl_associated_token_account::SplAssociatedTokenProgram::Token2022, }, 2_100_000, ); let ata = crate::solana_ata_stateful::derive_ata( &wallet, &mint, kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, ) .unwrap_or_else(|error| panic!("ATA derivation failed: {error}")); let mut cache = crate::solana_ata_stateful::AccountCache::new(); cache.insert( mint.0.clone(), std::option::Option::Some(crate::solana_ata_stateful::tests::mint_account( kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, )), ); cache.insert( ata.0, std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, &mint, &crate::solana_ata_stateful::tests::pubkey(kb_program_ids::CONFIG_PROGRAM_ID), )), ); let report = crate::solana_ata_stateful::evaluate( &request, &crate::solana_ata_stateful::tests::plan(&request), "devnet", std::option::Option::Some(1), &cache, 2_000_000, 3_000_000, ) .unwrap_or_else(|error| panic!("ATA readiness failed: {error}")); assert_eq!(report.status, crate::SplAssociatedTokenAccountStatefulReadinessStatus::Blocked); assert!( report .checks .iter() .any(|check| return check.code == "idempotent_existing_ata_wallet_owner" && !check.passed) ); } #[test] fn recover_nested_validates_all_three_canonical_accounts_and_signers() { let wallet = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::STAKE_PROGRAM_ID); let owner_mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::VOTE_PROGRAM_ID); let nested_mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::CONFIG_PROGRAM_ID); let token_program = kb_program_ids::SPL_TOKEN_PROGRAM_ID; let request = crate::solana_ata_stateful::tests::request( kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::RecoverNested { wallet_owner: wallet.clone(), owner_mint: owner_mint.clone(), nested_mint: nested_mint.clone(), token_program: kb_executor_spl_associated_token_account::SplAssociatedTokenProgram::Classic, }, 0, ); let owner_ata = crate::solana_ata_stateful::derive_ata(&wallet, &owner_mint, token_program) .unwrap_or_else(|error| panic!("owner ATA failed: {error}")); let nested_ata = crate::solana_ata_stateful::derive_ata(&owner_ata, &nested_mint, token_program) .unwrap_or_else(|error| panic!("nested ATA failed: {error}")); let destination = crate::solana_ata_stateful::derive_ata(&wallet, &nested_mint, token_program) .unwrap_or_else(|error| panic!("destination ATA failed: {error}")); let mut cache = crate::solana_ata_stateful::AccountCache::new(); cache.insert( owner_mint.0.clone(), std::option::Option::Some(crate::solana_ata_stateful::tests::mint_account( token_program, )), ); cache.insert( nested_mint.0.clone(), std::option::Option::Some(crate::solana_ata_stateful::tests::mint_account( token_program, )), ); cache.insert( owner_ata.0.clone(), std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( token_program, &owner_mint, &wallet, )), ); cache.insert( nested_ata.0, std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( token_program, &nested_mint, &owner_ata, )), ); cache.insert( destination.0, std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( token_program, &nested_mint, &wallet, )), ); let report = crate::solana_ata_stateful::evaluate( &request, &crate::solana_ata_stateful::tests::plan(&request), "devnet", std::option::Option::Some(1), &cache, 2_000_000, 20_000, ) .unwrap_or_else(|error| panic!("ATA readiness failed: {error}")); assert_eq!(report.status, crate::SplAssociatedTokenAccountStatefulReadinessStatus::Ready); } #[test] fn creation_postcondition_requires_one_compatible_existing_ata() { let wallet = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::STAKE_PROGRAM_ID); let mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::VOTE_PROGRAM_ID); let operation = kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::CreateIdempotent { wallet_owner: wallet.clone(), mint: mint.clone(), token_program: kb_executor_spl_associated_token_account::SplAssociatedTokenProgram::Token2022, }; let ata = crate::solana_ata_stateful::derive_ata( &wallet, &mint, kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, ) .unwrap_or_else(|error| panic!("ATA derivation failed: {error}")); let mut cache = crate::solana_ata_stateful::AccountCache::new(); cache.insert( ata.0, std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, &mint, &wallet, )), ); let report = crate::solana_ata_stateful::evaluate_post_execution( kb_execution_api::ExecutionCluster::Devnet, &operation, std::option::Option::Some(12), &cache, ) .unwrap_or_else(|error| panic!("ATA postcondition failed: {error}")); assert_eq!(report.status, crate::SplAssociatedTokenAccountStatefulReadinessStatus::Ready); } #[test] fn recover_postcondition_requires_nested_closed_and_destination_compatible() { let wallet = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::STAKE_PROGRAM_ID); let owner_mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::VOTE_PROGRAM_ID); let nested_mint = crate::solana_ata_stateful::tests::pubkey(kb_program_ids::CONFIG_PROGRAM_ID); let token_program = kb_program_ids::SPL_TOKEN_PROGRAM_ID; let operation = kb_executor_spl_associated_token_account::SplAssociatedTokenAccountOperation::RecoverNested { wallet_owner: wallet.clone(), owner_mint: owner_mint.clone(), nested_mint: nested_mint.clone(), token_program: kb_executor_spl_associated_token_account::SplAssociatedTokenProgram::Classic, }; let owner_ata = crate::solana_ata_stateful::derive_ata(&wallet, &owner_mint, token_program) .unwrap_or_else(|error| panic!("owner ATA failed: {error}")); let nested_ata = crate::solana_ata_stateful::derive_ata(&owner_ata, &nested_mint, token_program) .unwrap_or_else(|error| panic!("nested ATA failed: {error}")); let destination = crate::solana_ata_stateful::derive_ata(&wallet, &nested_mint, token_program) .unwrap_or_else(|error| panic!("destination ATA failed: {error}")); let mut cache = crate::solana_ata_stateful::AccountCache::new(); cache.insert( owner_ata.0, std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( token_program, &owner_mint, &wallet, )), ); cache.insert(nested_ata.0, std::option::Option::None); cache.insert( destination.0, std::option::Option::Some(crate::solana_ata_stateful::tests::token_account( token_program, &nested_mint, &wallet, )), ); let report = crate::solana_ata_stateful::evaluate_post_execution( kb_execution_api::ExecutionCluster::Devnet, &operation, std::option::Option::Some(13), &cache, ) .unwrap_or_else(|error| panic!("RecoverNested postcondition failed: {error}")); assert_eq!(report.status, crate::SplAssociatedTokenAccountStatefulReadinessStatus::Ready); } }