use std::time::{Duration, SystemTime, UNIX_EPOCH};
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_program_pack::Pack;
use solana_pubkey::Pubkey;
use solana_sdk::hash::hashv;
use solana_system_interface::instruction::create_account_with_seed;
use spl_token::state::Account as SplTokenAccount;
use spl_token_interface::{
instruction::{close_account, initialize_account3},
native_mint, ID as TOKEN_PROGRAM_ID,
};
use crate::token::{
account_planner::{TokenAccountInstructions, TokenAccountStrategy},
account_state::TokenAccountState,
adapter::{prepare_token_accounts_workspace, strategies_to_intent},
NativeMintWrappingStrategy, WorkspacePlanConfig,
};
pub async fn prepare_seeded_wsol_legacy(
rpc: &RpcClient,
owner: Pubkey,
spec: Vec<TokenAccountStrategy>,
state: TokenAccountState,
config: &WorkspacePlanConfig,
) -> Result<TokenAccountInstructions, Box<dyn std::error::Error>> {
let mints: Vec<Pubkey> = spec.iter().map(TokenAccountStrategy::mint).collect();
let native_mint_index = mints
.iter()
.position(|m| *m == native_mint::ID)
.ok_or("prepare_seeded_wsol_legacy called without native mint in spec")?;
let native_strategy = spec[native_mint_index];
let spec_without_wsol: Vec<TokenAccountStrategy> =
spec.iter().copied().filter(|s| s.mint() != native_mint::ID).collect();
let state_without_wsol = TokenAccountState {
owner: state.owner,
mints: state
.mints
.iter()
.filter(|(k, _)| **k != native_mint::ID)
.map(|(k, v)| (*k, v.clone()))
.collect(),
};
let inner_config = WorkspacePlanConfig {
wsol_strategy: NativeMintWrappingStrategy::Ata,
enforce_balance: config.enforce_balance,
};
let intent_without_wsol = strategies_to_intent(&spec_without_wsol, &inner_config);
let rent_exempt = rpc.get_minimum_balance_for_rent_exemption(SplTokenAccount::LEN).await?;
let mut result = prepare_token_accounts_workspace(
&state_without_wsol,
&intent_without_wsol,
rent_exempt,
&inner_config,
)?;
let mut lamports = rent_exempt;
if let TokenAccountStrategy::WithBalance(_, balance) = native_strategy {
lamports += balance;
}
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or(Duration::from_secs(0))
.as_millis()
.to_string();
let hash_result = hashv(&[owner.as_ref(), seed.as_bytes(), TOKEN_PROGRAM_ID.as_ref()]);
let pubkey = Pubkey::from(hash_result.to_bytes());
result.create_instructions.push(create_account_with_seed(
&owner,
&pubkey,
&owner,
&seed,
lamports,
SplTokenAccount::LEN as u64,
&TOKEN_PROGRAM_ID,
));
result.create_instructions.push(initialize_account3(
&TOKEN_PROGRAM_ID,
&pubkey,
&native_mint::ID,
&owner,
)?);
result.cleanup_instructions.push(close_account(
&TOKEN_PROGRAM_ID,
&pubkey,
&owner,
&owner,
&[],
)?);
result.token_account_addresses.insert(native_mint::ID, pubkey);
Ok(result)
}