account_compression/instructions/
resize_registered_program_account.rs

1use aligned_sized::aligned_sized;
2use anchor_lang::{
3    prelude::*,
4    solana_program::{program::invoke, system_instruction::transfer},
5    Discriminator,
6};
7use bytemuck::from_bytes_mut;
8
9use crate::{utils::constants::CPI_AUTHORITY_PDA_SEED, RegisteredProgram};
10
11#[repr(C)]
12#[derive(Debug, Copy)]
13#[account]
14#[aligned_sized(anchor)]
15pub struct RegisteredProgramV1 {
16    pub registered_program_id: Pubkey,
17    pub group_authority_pda: Pubkey,
18}
19
20#[derive(Accounts)]
21pub struct ResizeRegisteredProgramPda<'info> {
22    /// CHECK: unchecked since any RegisteredProgramV1 must be resized to continue operation.
23    #[account(mut)]
24    pub authority: Signer<'info>,
25    /// CHECK: only V1 accounts should be resized. We can detect V1 accounts based on the data length.
26    #[account(mut, constraint= registered_program_pda.to_account_info().data_len() == RegisteredProgramV1::LEN)]
27    pub registered_program_pda: AccountInfo<'info>,
28    pub system_program: Program<'info, System>,
29}
30
31pub fn process_resize_registered_program_pda<'info>(
32    ctx: Context<'_, '_, '_, 'info, ResizeRegisteredProgramPda<'info>>,
33) -> Result<()> {
34    // account checks
35    // 1. Discriminator check
36    // 2. Ownership check
37    {
38        let discriminator_bytes = &ctx.accounts.registered_program_pda.try_borrow_data()?[0..8];
39        if discriminator_bytes != RegisteredProgram::DISCRIMINATOR {
40            return err!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch);
41        }
42        light_account_checks::checks::check_owner(
43            &crate::ID.to_bytes(),
44            &ctx.accounts.registered_program_pda,
45        )
46        .map_err(ProgramError::from)?;
47    }
48    let pre_account = RegisteredProgramV1::try_from_slice(
49        &ctx.accounts.registered_program_pda.try_borrow_mut_data()?[8..],
50    )?;
51    // Resize account.
52    {
53        let rent = Rent::get()?;
54        let new_minimum_balance = rent.minimum_balance(RegisteredProgram::LEN);
55        let account_info = ctx.accounts.registered_program_pda.to_account_info();
56        let lamports_diff = new_minimum_balance.saturating_sub(account_info.lamports());
57        invoke(
58            &transfer(
59                ctx.accounts.authority.key,
60                ctx.accounts.registered_program_pda.key,
61                lamports_diff,
62            ),
63            &[
64                ctx.accounts.authority.to_account_info(),
65                ctx.accounts.registered_program_pda.to_account_info(),
66                ctx.accounts.system_program.to_account_info(),
67            ],
68        )?;
69
70        account_info.realloc(RegisteredProgram::LEN, false)?;
71    }
72
73    // Initialize registered_program_signer_pda with derived signer pda.
74    let account_info = ctx.accounts.registered_program_pda.to_account_info();
75    let mut data = account_info.try_borrow_mut_data()?;
76    let account = from_bytes_mut::<RegisteredProgram>(&mut data[8..]);
77
78    let derived_signer = Pubkey::find_program_address(
79        &[CPI_AUTHORITY_PDA_SEED],
80        &pre_account.registered_program_id,
81    )
82    .0;
83    account.registered_program_signer_pda = derived_signer;
84    Ok(())
85}