Skip to main content

light_system_program/invoke/
address.rs

1use account_compression::utils::constants::CPI_AUTHORITY_PDA_SEED;
2use anchor_lang::{prelude::*, Bumps};
3
4use crate::{
5    constants::CPI_AUTHORITY_PDA_BUMP,
6    invoke_cpi::verify_signer::check_program_owner_address_merkle_tree,
7    sdk::{
8        accounts::{InvokeAccounts, SignerAccounts},
9        address::derive_address,
10    },
11    NewAddressParamsPacked,
12};
13
14pub fn derive_new_addresses(
15    new_address_params: &[NewAddressParamsPacked],
16    num_input_compressed_accounts: usize,
17    remaining_accounts: &[AccountInfo],
18    compressed_account_addresses: &mut [Option<[u8; 32]>],
19    new_addresses: &mut [[u8; 32]],
20) -> Result<()> {
21    new_address_params
22        .iter()
23        .enumerate()
24        .try_for_each(|(i, new_address_params)| {
25            let address = derive_address(
26                &remaining_accounts[new_address_params.address_merkle_tree_account_index as usize]
27                    .key(),
28                &new_address_params.seed,
29            )
30            .map_err(ProgramError::from)?;
31            // We are inserting addresses into two vectors to avoid unwrapping
32            // the option in following functions.
33            compressed_account_addresses[i + num_input_compressed_accounts] = Some(address);
34            new_addresses[i] = address;
35            Ok(())
36        })
37}
38
39pub fn insert_addresses_into_address_merkle_tree_queue<
40    'a,
41    'b,
42    'c: 'info,
43    'info,
44    A: InvokeAccounts<'info> + SignerAccounts<'info> + Bumps,
45>(
46    ctx: &'a Context<'a, 'b, 'c, 'info, A>,
47    addresses: &'a [[u8; 32]],
48    new_address_params: &'a [NewAddressParamsPacked],
49    invoking_program: &Option<Pubkey>,
50) -> anchor_lang::Result<Option<(u8, u64)>> {
51    let mut remaining_accounts = Vec::<AccountInfo>::with_capacity(new_address_params.len() * 2);
52    let mut network_fee_bundle = None;
53
54    new_address_params.iter().try_for_each(|params| {
55        remaining_accounts
56            .push(ctx.remaining_accounts[params.address_queue_account_index as usize].clone());
57
58        remaining_accounts.push(
59            ctx.remaining_accounts[params.address_merkle_tree_account_index as usize].clone(),
60        );
61        // If at least one new address is created an address network fee is
62        // paid.The network fee is paid once per transaction, defined in the
63        // state Merkle tree and transferred to the nullifier queue because the
64        // nullifier queue is mutable. The network fee field in the queue is not
65        // used.
66        let network_fee = check_program_owner_address_merkle_tree(
67            &ctx.remaining_accounts[params.address_merkle_tree_account_index as usize],
68            invoking_program,
69        )?;
70        // We select the first network fee we find. All Merkle trees are
71        // initialized with the same network fee.
72        if network_fee_bundle.is_none() && network_fee.is_some() {
73            network_fee_bundle = Some((params.address_queue_account_index, network_fee.unwrap()));
74        }
75        anchor_lang::Result::Ok(())
76    })?;
77
78    insert_addresses_cpi(
79        ctx.accounts.get_account_compression_program(),
80        &ctx.accounts.get_fee_payer().to_account_info(),
81        ctx.accounts.get_account_compression_authority(),
82        &ctx.accounts.get_registered_program_pda().to_account_info(),
83        &ctx.accounts.get_system_program().to_account_info(),
84        remaining_accounts,
85        addresses.to_vec(),
86    )?;
87    Ok(network_fee_bundle)
88}
89
90#[allow(clippy::too_many_arguments)]
91pub fn insert_addresses_cpi<'a, 'b>(
92    account_compression_program_id: &'b AccountInfo<'a>,
93    fee_payer: &'b AccountInfo<'a>,
94    authority: &'b AccountInfo<'a>,
95    registered_program_pda: &'b AccountInfo<'a>,
96    system_program: &'b AccountInfo<'a>,
97    remaining_accounts: Vec<AccountInfo<'a>>,
98    addresses: Vec<[u8; 32]>,
99) -> Result<()> {
100    let bump = &[CPI_AUTHORITY_PDA_BUMP];
101    let seeds = &[&[CPI_AUTHORITY_PDA_SEED, bump][..]];
102    let accounts = account_compression::cpi::accounts::InsertIntoQueues {
103        fee_payer: fee_payer.to_account_info(),
104        authority: authority.to_account_info(),
105        registered_program_pda: Some(registered_program_pda.to_account_info()),
106        system_program: system_program.to_account_info(),
107    };
108
109    let mut cpi_ctx =
110        CpiContext::new_with_signer(account_compression_program_id.clone(), accounts, seeds);
111    cpi_ctx.remaining_accounts.extend(remaining_accounts);
112
113    account_compression::cpi::insert_addresses(cpi_ctx, addresses)
114}