2

Let's say I have a PDA which maintains the global state of my program. This is like a singleton. And the following snippets of code initialize it :

pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
    require!(
        !ctx.accounts.global.initialized,
        ErrorCodes::AlreadyInitialized
    );

    ctx.accounts.global.authority = *ctx.accounts.user.key;
    ctx.accounts.global.initialized = true;

    Ok(())
}

And here is the accounts struct:

#[account]
pub struct Global {
    pub authority: Pubkey,
    pub initialized: bool,
    pub some_things_here: bool;
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8+1+1, seeds = [b"global"], bump)]
    pub global: Account<'info, Global>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

It is entirely possible that somebody could frontrun the initialization. For example:

  1. Deploy the program
  2. Attacker calls initialize before the honest admin can call initialize
  3. Now the attacker has full control and is the authority

How can I prevent this attack (I'm using anchor)? Does there exist a best practice?

1 Answer 1

3

You can for example add a check on who can call the function like so:

https://beta.solpg.io/tutorials/battle-coins

const ADMIN_PUBKEY: Pubkey = pubkey!("REPLACE_WITH_YOUR_WALLET_PUBKEY");
...
#[account(
    mut,
    address = ADMIN_PUBKEY
)]
pub admin: Signer<'info>,
2
  • Is there a way to do this programatically or do I have to manually copy+paste my key? Commented Jan 6 at 16:15
  • By programatically do it what do you mean? You're adding code to automatically manage. You can have more code that allows admin key to change as well.
    – Jacob Creech
    Commented Jan 6 at 18:24

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.