5

I want to transfer ownership of my program owned account to the system account.

From the docs, I understand that ...

Only the owner of the account may change owner.
- And only if the account is writable.
- And only if the account is not executable.
- And only if the data is zero-initialized or empty.

Without requiring a signature, I should be able to change ownership of account A from program B to the system program, as long as the ownership transfer takes place in program B since it owns account A.

Account A should be mutable and be zero initialized.

// ANCHOR 0.25
pub fn transfer_owner(ctx: Context<TransferOwner>) -> Result<()> {
    let transfer_account = &mut ctx.accounts.account_to_transfer;
    let acc_info = transfer_account.to_account_info();
    acc_info.assign(&system_program::id());
    Ok(())
}

#[derive(Accounts)]
pub struct TransferOwner<'info> {
    // zero init the data
    #[account(
        mut,
        realloc = 40 ,
        realloc::payer = payer,
        realloc::zero = true,
    )]
    pub account_to_transfer: Account<'info, OwnedAccount>, 
    #[account(mut)]
    pub payer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Yet whenever I call this I get

Transaction simulation failed: Error processing Instruction 0: instruction illegally modified the program id of an account

const transferOwnerTx = await program.methods
    .transferOwner()
    .accounts({
      accountToTransfer: transferKeypair.publicKey,
      payer: fundingKeypair.publicKey,
    })
    .signers([fundingKeypair])
    .rpc();

I can guarantee that the transferKeypair is owned by my program.

Adding signature doesn't change anything, which makes sense because its up to my program implementation to decide if I want that verification. Here I don't.

(I renamed some variables in the code snippet, regardless of errors in that I can also guarantee my error isn't typo related)

Any ideas? I know transferring ownership unsafely like this doesn't have many usecases but I wanted to test out the full permissions of non-spl/native program owned accounts.

2 Answers 2

2

Only the data needs to be zeroed out in order to change the ownership of an account. Because Anchor stores the type of the account in the first few bytes, you might need to manually clear all the bytes before reassigning, ie:

pub fn transfer_owner(ctx: Context<TransferOwner>) -> Result<()> {
    let transfer_account = &mut ctx.accounts.account_to_transfer;
    let acc_info = transfer_account.to_account_info();
    acc_info.assign(&system_program::id());
    let mut account_data = acc_info.data.borrow_mut();
    let data_len = account_data.len();
    solana_program::program_memory::sol_memset(*account_data, 0, data_len);
    Ok(())
}

Or to realloc by hand:

pub fn transfer_owner(ctx: Context<TransferOwner>) -> Result<()> {
    let transfer_account = &mut ctx.accounts.account_to_transfer;
    let acc_info = transfer_account.to_account_info();
    acc_info.assign(&system_program::id());
    acc_info.realloc(0, false)?;
    Ok(())
}
1

It's possible the account needs to both 0 space and be zeroed out when you do the transfer. You have realloc = 40. Have you tried with realloc = 0?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.