light_compressed_pda/invoke/
instruction.rs

1use account_compression::program::AccountCompression;
2use anchor_lang::prelude::*;
3
4use crate::{
5    errors::CompressedPdaError,
6    invoke::sol_compression::COMPRESSED_SOL_PDA_SEED,
7    sdk::{
8        accounts::{InvokeAccounts, SignerAccounts},
9        compressed_account::{CompressedAccount, PackedCompressedAccountWithMerkleContext},
10    },
11};
12
13use super::processor::CompressedProof;
14
15/// These are the base accounts additionally Merkle tree and queue accounts are required.
16/// These additional accounts are passed as remaining accounts.
17/// 1 Merkle tree for each input compressed account one queue and Merkle tree account each for each output compressed account.
18#[derive(Accounts)]
19pub struct InvokeInstruction<'info> {
20    #[account(mut)]
21    pub fee_payer: Signer<'info>,
22    pub authority: Signer<'info>,
23    /// CHECK: this account
24    #[account(
25    seeds = [&crate::ID.to_bytes()], bump, seeds::program = &account_compression::ID,
26    )]
27    pub registered_program_pda:
28        Account<'info, account_compression::instructions::register_program::RegisteredProgram>,
29    /// CHECK: this account
30    pub noop_program: UncheckedAccount<'info>,
31    /// CHECK: this account in psp account compression program
32    #[account(seeds = [b"cpi_authority"], bump)]
33    pub account_compression_authority: UncheckedAccount<'info>,
34    /// CHECK: this account in psp account compression program
35    pub account_compression_program: Program<'info, AccountCompression>,
36    #[account(
37        mut,
38        seeds = [COMPRESSED_SOL_PDA_SEED], bump
39    )]
40    pub compressed_sol_pda: Option<UncheckedAccount<'info>>,
41    #[account(mut)]
42    pub compression_recipient: Option<UncheckedAccount<'info>>,
43    pub system_program: Program<'info, System>,
44}
45
46impl<'info> SignerAccounts<'info> for InvokeInstruction<'info> {
47    fn get_fee_payer(&self) -> &Signer<'info> {
48        &self.fee_payer
49    }
50
51    fn get_authority(&self) -> &Signer<'info> {
52        &self.authority
53    }
54}
55
56impl<'info> InvokeAccounts<'info> for InvokeInstruction<'info> {
57    fn get_registered_program_pda(
58        &self,
59    ) -> &Account<'info, account_compression::instructions::register_program::RegisteredProgram>
60    {
61        &self.registered_program_pda
62    }
63
64    fn get_noop_program(&self) -> &UncheckedAccount<'info> {
65        &self.noop_program
66    }
67
68    fn get_account_compression_authority(&self) -> &UncheckedAccount<'info> {
69        &self.account_compression_authority
70    }
71
72    fn get_account_compression_program(&self) -> &Program<'info, AccountCompression> {
73        &self.account_compression_program
74    }
75
76    fn get_system_program(&self) -> &Program<'info, System> {
77        &self.system_program
78    }
79    fn get_compressed_sol_pda(&self) -> Option<&UncheckedAccount<'info>> {
80        self.compressed_sol_pda.as_ref()
81    }
82    fn get_compression_recipient(&self) -> Option<&UncheckedAccount<'info>> {
83        self.compression_recipient.as_ref()
84    }
85}
86
87// TODO: add checks for lengths of vectors
88#[derive(Debug, PartialEq, Default, Clone, AnchorSerialize, AnchorDeserialize)]
89pub struct InstructionDataInvoke {
90    pub proof: Option<CompressedProof>,
91    pub input_root_indices: Vec<u16>,
92    pub input_compressed_accounts_with_merkle_context:
93        Vec<PackedCompressedAccountWithMerkleContext>,
94    pub output_compressed_accounts: Vec<CompressedAccount>,
95    /// The indices of the accounts in the output state merkle tree.
96    pub output_state_merkle_tree_account_indices: Vec<u8>,
97    pub relay_fee: Option<u64>,
98    pub new_address_params: Vec<NewAddressParamsPacked>,
99    pub compression_lamports: Option<u64>,
100    pub is_compress: bool,
101}
102
103#[derive(Debug, PartialEq, Default, Clone, Copy, AnchorSerialize, AnchorDeserialize)]
104pub struct NewAddressParamsPacked {
105    pub seed: [u8; 32],
106    pub address_queue_account_index: u8,
107    pub address_merkle_tree_account_index: u8,
108    pub address_merkle_tree_root_index: u16,
109}
110
111#[derive(Debug, PartialEq, Default, Clone, AnchorSerialize, AnchorDeserialize)]
112pub struct NewAddressParams {
113    pub seed: [u8; 32],
114    pub address_queue_pubkey: Pubkey,
115    pub address_merkle_tree_pubkey: Pubkey,
116    pub address_merkle_tree_root_index: u16,
117}
118
119impl InstructionDataInvoke {
120    /// Checks that the lengths of the vectors are consistent with each other.
121    /// Note that this function does not check the inputs themselves just plausible of the lengths.
122    /// input roots must be the same length as input compressed accounts
123    /// output compressed accounts must be the same length as output state merkle tree account indices
124    pub fn check_input_lengths(&self) -> Result<()> {
125        if self.input_root_indices.len() != self.input_compressed_accounts_with_merkle_context.len()
126        {
127            msg!("input_root_indices.len() {} != {} input_compressed_accounts_with_merkle_context.len()",
128                self.input_root_indices.len(), self.input_compressed_accounts_with_merkle_context.len()
129            );
130            msg!("self {:?}", self);
131            return Err(CompressedPdaError::LengthMismatch.into());
132        }
133
134        if self.output_compressed_accounts.len()
135            != self.output_state_merkle_tree_account_indices.len()
136        {
137            msg!("output_compressed_accounts.len() {} != {} output_state_merkle_tree_account_indices.len()",
138                self.output_compressed_accounts.len(), self.output_state_merkle_tree_account_indices.len()
139            );
140            msg!("self {:?}", self);
141            return Err(CompressedPdaError::LengthMismatch.into());
142        }
143
144        Ok(())
145    }
146}