use light_client::rpc::{Rpc, RpcError};
use light_token::{
constants::{SPL_TOKEN_2022_PROGRAM_ID, SPL_TOKEN_PROGRAM_ID},
instruction::TransferToSpl,
spl_interface::{find_spl_interface_pda, has_restricted_extensions},
};
use solana_keypair::Keypair;
use solana_pubkey::Pubkey;
use solana_signature::Signature;
use solana_signer::Signer;
#[derive(Default, Clone, Debug)]
pub struct Unwrap {
pub source: Pubkey,
pub destination_spl_ata: Pubkey,
pub mint: Pubkey,
pub amount: u64,
pub decimals: u8,
}
impl Unwrap {
pub async fn execute<R: Rpc>(
self,
rpc: &mut R,
payer: &Keypair,
authority: &Keypair,
) -> Result<Signature, RpcError> {
let destination_account_info = rpc
.get_account(self.destination_spl_ata)
.await?
.ok_or_else(|| {
RpcError::CustomError("Destination SPL token account not found".to_string())
})?;
let spl_token_program = destination_account_info.owner;
if spl_token_program != SPL_TOKEN_PROGRAM_ID
&& spl_token_program != SPL_TOKEN_2022_PROGRAM_ID
{
return Err(RpcError::CustomError(format!(
"Destination SPL token account {} is owned by an unsupported program {}. \
Expected SPL Token ({}) or Token-2022 ({}).",
self.destination_spl_ata,
destination_account_info.owner,
SPL_TOKEN_PROGRAM_ID,
SPL_TOKEN_2022_PROGRAM_ID
)));
}
let restricted = if spl_token_program == SPL_TOKEN_2022_PROGRAM_ID {
let mint_account = rpc
.get_account(self.mint)
.await?
.ok_or_else(|| RpcError::CustomError("Mint account not found".to_string()))?;
has_restricted_extensions(&mint_account.data)
} else {
false
};
let (spl_interface_pda, bump) = find_spl_interface_pda(&self.mint, restricted);
let ix = TransferToSpl {
source: self.source,
destination_spl_token_account: self.destination_spl_ata,
amount: self.amount,
authority: authority.pubkey(),
mint: self.mint,
payer: payer.pubkey(),
spl_interface_pda,
spl_interface_pda_bump: bump,
decimals: self.decimals,
spl_token_program,
}
.instruction()
.map_err(|e| RpcError::CustomError(format!("Failed to create instruction: {}", e)))?;
let mut signers: Vec<&Keypair> = vec![payer];
if authority.pubkey() != payer.pubkey() {
signers.push(authority);
}
rpc.create_and_send_transaction(&[ix], &payer.pubkey(), &signers)
.await
}
}