light_token_client/actions/
unwrap.rs1use light_client::rpc::{Rpc, RpcError};
6use light_token::{
7 constants::{SPL_TOKEN_2022_PROGRAM_ID, SPL_TOKEN_PROGRAM_ID},
8 instruction::TransferToSpl,
9 spl_interface::{find_spl_interface_pda, has_restricted_extensions},
10};
11use solana_keypair::Keypair;
12use solana_pubkey::Pubkey;
13use solana_signature::Signature;
14use solana_signer::Signer;
15
16#[derive(Default, Clone, Debug)]
31pub struct Unwrap {
32 pub source: Pubkey,
34 pub destination_spl_ata: Pubkey,
36 pub mint: Pubkey,
38 pub amount: u64,
40 pub decimals: u8,
42}
43
44impl Unwrap {
45 pub async fn execute<R: Rpc>(
55 self,
56 rpc: &mut R,
57 payer: &Keypair,
58 authority: &Keypair,
59 ) -> Result<Signature, RpcError> {
60 let destination_account_info = rpc
62 .get_account(self.destination_spl_ata)
63 .await?
64 .ok_or_else(|| {
65 RpcError::CustomError("Destination SPL token account not found".to_string())
66 })?;
67
68 let spl_token_program = destination_account_info.owner;
69
70 if spl_token_program != SPL_TOKEN_PROGRAM_ID
72 && spl_token_program != SPL_TOKEN_2022_PROGRAM_ID
73 {
74 return Err(RpcError::CustomError(format!(
75 "Destination SPL token account {} is owned by an unsupported program {}. \
76 Expected SPL Token ({}) or Token-2022 ({}).",
77 self.destination_spl_ata,
78 destination_account_info.owner,
79 SPL_TOKEN_PROGRAM_ID,
80 SPL_TOKEN_2022_PROGRAM_ID
81 )));
82 }
83
84 let restricted = if spl_token_program == SPL_TOKEN_2022_PROGRAM_ID {
86 let mint_account = rpc
87 .get_account(self.mint)
88 .await?
89 .ok_or_else(|| RpcError::CustomError("Mint account not found".to_string()))?;
90 has_restricted_extensions(&mint_account.data)
91 } else {
92 false
93 };
94
95 let (spl_interface_pda, bump) = find_spl_interface_pda(&self.mint, restricted);
96
97 let ix = TransferToSpl {
98 source: self.source,
99 destination_spl_token_account: self.destination_spl_ata,
100 amount: self.amount,
101 authority: authority.pubkey(),
102 mint: self.mint,
103 payer: payer.pubkey(),
104 spl_interface_pda,
105 spl_interface_pda_bump: bump,
106 decimals: self.decimals,
107 spl_token_program,
108 }
109 .instruction()
110 .map_err(|e| RpcError::CustomError(format!("Failed to create instruction: {}", e)))?;
111
112 let mut signers: Vec<&Keypair> = vec![payer];
113 if authority.pubkey() != payer.pubkey() {
114 signers.push(authority);
115 }
116
117 rpc.create_and_send_transaction(&[ix], &payer.pubkey(), &signers)
118 .await
119 }
120}