light_system_program/invoke_cpi/
instruction.rs

1use account_compression::{program::AccountCompression, utils::constants::CPI_AUTHORITY_PDA_SEED};
2use anchor_lang::{
3    prelude::*, solana_program::pubkey::Pubkey, system_program::System, AnchorDeserialize,
4    AnchorSerialize,
5};
6
7use super::account::CpiContextAccount;
8use crate::{
9    invoke::{processor::CompressedProof, sol_compression::SOL_POOL_PDA_SEED},
10    sdk::{
11        accounts::{InvokeAccounts, SignerAccounts},
12        compressed_account::PackedCompressedAccountWithMerkleContext,
13        CompressedCpiContext,
14    },
15    NewAddressParamsPacked, OutputCompressedAccountWithPackedContext,
16};
17
18#[derive(Accounts)]
19pub struct InvokeCpiInstruction<'info> {
20    /// Fee payer needs to be mutable to pay rollover and protocol fees.
21    #[account(mut)]
22    pub fee_payer: Signer<'info>,
23    pub authority: Signer<'info>,
24    /// CHECK:
25    #[account(
26    seeds = [&crate::ID.to_bytes()], bump, seeds::program = &account_compression::ID,
27    )]
28    pub registered_program_pda: AccountInfo<'info>,
29    /// CHECK: checked in emit_event.rs.
30    pub noop_program: UncheckedAccount<'info>,
31    /// CHECK:
32    #[account(seeds = [CPI_AUTHORITY_PDA_SEED], bump)]
33    pub account_compression_authority: UncheckedAccount<'info>,
34    /// CHECK:
35    pub account_compression_program: Program<'info, AccountCompression>,
36    /// CHECK: checked in cpi_signer_check.
37    pub invoking_program: UncheckedAccount<'info>,
38    #[account(
39        mut,
40        seeds = [SOL_POOL_PDA_SEED], bump
41    )]
42    pub sol_pool_pda: Option<AccountInfo<'info>>,
43    #[account(mut)]
44    pub decompression_recipient: Option<AccountInfo<'info>>,
45    pub system_program: Program<'info, System>,
46    #[account(mut)]
47    pub cpi_context_account: Option<Account<'info, CpiContextAccount>>,
48}
49
50impl<'info> SignerAccounts<'info> for InvokeCpiInstruction<'info> {
51    fn get_fee_payer(&self) -> &Signer<'info> {
52        &self.fee_payer
53    }
54
55    fn get_authority(&self) -> &Signer<'info> {
56        &self.authority
57    }
58}
59
60impl<'info> InvokeAccounts<'info> for InvokeCpiInstruction<'info> {
61    fn get_registered_program_pda(&self) -> &AccountInfo<'info> {
62        &self.registered_program_pda
63    }
64
65    fn get_noop_program(&self) -> &UncheckedAccount<'info> {
66        &self.noop_program
67    }
68
69    fn get_account_compression_authority(&self) -> &UncheckedAccount<'info> {
70        &self.account_compression_authority
71    }
72
73    fn get_account_compression_program(&self) -> &Program<'info, AccountCompression> {
74        &self.account_compression_program
75    }
76
77    fn get_sol_pool_pda(&self) -> Option<&AccountInfo<'info>> {
78        self.sol_pool_pda.as_ref()
79    }
80
81    fn get_decompression_recipient(&self) -> Option<&AccountInfo<'info>> {
82        self.decompression_recipient.as_ref()
83    }
84
85    fn get_system_program(&self) -> &Program<'info, System> {
86        &self.system_program
87    }
88}
89
90#[derive(Debug, PartialEq, Default, Clone, AnchorSerialize, AnchorDeserialize)]
91pub struct InstructionDataInvokeCpi {
92    pub proof: Option<CompressedProof>,
93    pub new_address_params: Vec<NewAddressParamsPacked>,
94    pub input_compressed_accounts_with_merkle_context:
95        Vec<PackedCompressedAccountWithMerkleContext>,
96    pub output_compressed_accounts: Vec<OutputCompressedAccountWithPackedContext>,
97    pub relay_fee: Option<u64>,
98    pub compress_or_decompress_lamports: Option<u64>,
99    pub is_compress: bool,
100    pub cpi_context: Option<CompressedCpiContext>,
101}
102
103impl InstructionDataInvokeCpi {
104    pub fn combine(&mut self, other: &[InstructionDataInvokeCpi]) {
105        for other in other {
106            self.new_address_params
107                .extend_from_slice(&other.new_address_params);
108            self.input_compressed_accounts_with_merkle_context
109                .extend_from_slice(&other.input_compressed_accounts_with_merkle_context);
110            self.output_compressed_accounts
111                .extend_from_slice(&other.output_compressed_accounts);
112        }
113    }
114}
115#[cfg(test)]
116mod tests {
117    use std::vec;
118
119    use crate::{
120        invoke::processor::CompressedProof,
121        sdk::compressed_account::PackedCompressedAccountWithMerkleContext,
122        InstructionDataInvokeCpi, NewAddressParamsPacked, OutputCompressedAccountWithPackedContext,
123    };
124
125    // test combine instruction data transfer
126    #[test]
127    fn test_combine_instruction_data_transfer() {
128        let mut instruction_data_transfer = InstructionDataInvokeCpi {
129            proof: Some(CompressedProof {
130                a: [0; 32],
131                b: [0; 64],
132                c: [0; 32],
133            }),
134            new_address_params: vec![NewAddressParamsPacked::default()],
135            input_compressed_accounts_with_merkle_context: vec![
136                PackedCompressedAccountWithMerkleContext::default(),
137            ],
138            output_compressed_accounts: vec![OutputCompressedAccountWithPackedContext::default()],
139            relay_fee: Some(1),
140            compress_or_decompress_lamports: Some(1),
141            is_compress: true,
142            cpi_context: None,
143        };
144        let other = InstructionDataInvokeCpi {
145            proof: Some(CompressedProof {
146                a: [0; 32],
147                b: [0; 64],
148                c: [0; 32],
149            }),
150            input_compressed_accounts_with_merkle_context: vec![
151                PackedCompressedAccountWithMerkleContext::default(),
152            ],
153            output_compressed_accounts: vec![OutputCompressedAccountWithPackedContext::default()],
154            relay_fee: Some(1),
155            compress_or_decompress_lamports: Some(1),
156            is_compress: true,
157            new_address_params: vec![NewAddressParamsPacked::default()],
158            cpi_context: None,
159        };
160        instruction_data_transfer.combine(&[other]);
161        assert_eq!(instruction_data_transfer.new_address_params.len(), 2);
162        assert_eq!(
163            instruction_data_transfer
164                .input_compressed_accounts_with_merkle_context
165                .len(),
166            2
167        );
168        assert_eq!(
169            instruction_data_transfer.output_compressed_accounts.len(),
170            2
171        );
172    }
173}