4

This was an accidental discovery when playing with the Solana Playground, but it surprised me and feels like a bug. I'm wondering why it works this way.

Example: https://beta.solpg.io/62d67703f6273245aca4f5fe

This is just the default starter code, I'm using a share link in case it changes in future.

The initialize instruction is initializing a new account:

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 8)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

If you connect the playground wallet, and airdrop some more SOL so it can be built/deployed, then it can be tested in the playground:

image showing playground test UI with addresses populated

I accidentally set my address (of the playground wallet) to both the new_account and signer fields, instead of just signer.

I'd have expected this to fail. My account is not empty, it has SOL and it has transactions (the airdrops). I've seen Anchor refuse to initialize an account because it's not empty before. But it succeeded, seemingly initialising my account to be this NewAccount.

And now if I try to run the same command again, this time using a random key for newAccount and myself only as signer, I get an error saying my account can't be used to pay transaction fees:

Testing 'initialize'...
❌  Test 'initialize' failed: 
Reason: This account may not be used to pay transaction fees.

The account still has its SOL balance, but it's no longer recognised as an account that can perform transactions. If this was a wallet I cared about/that had assets, I'm not sure how I'd recover from this.

Why wouldn't Solana have refused to initialize the account on my first call?

The wallet account: https://explorer.solana.com/address/5nRUXQaYp2rV6HpBNJj9b6729oL5dm6ZTMokATaPZvjk?cluster=devnet

1 Answer 1

3

What an instruction does and how account data is structured is opaque to the runtime. If a specific program has conditions such that pubkeys/addresses sharing roles are conflicts, that's on the program to declare and enforce (ie this Initialize instruction should have prevented these conditions if they are undesirable).

However, what you've run into here is that only system accounts (those owned by the system program and carrying 0-bytes of account data) are allowed to pay fees. In reassigning your "wallet" account to another program, you've sacrificed this ability.

All is not lost though. The program needs to declare a transfer instruction to allow manipulation of the lamports balance. Then either all but the rent-exempt-reserve can be transferred out to a new "wallet" account, or the full balance can be temporarily transferred out to another "wallet" account, which will result in the account being reaped by the runtime, then the lamports can be transferred back, reinitializing the address as a system account. In all cases you will need another account to act as fee-payer for the transactions performing these actions

2
  • Thanks for the response! So it definitely makes sense to me that after being put in this state the account can't pay fees. I thought there'd still be a way to get the assets too - like you said with another signer covering fees. Thinking about it more though I'm wondering how this isn't a vulnerability for users? I don't think a wallet would present this Initialize instruction as dangerous, it just costs a tiny amount of SOL. I don't think they'd inspect accounts? But calling it would leave the user's wallet in a state where they can't use any of their wallet's features to transact.
    – Callum M
    Jul 19 at 20:52
  • This goes doubly if the program needs to implement an instruction to rescue the account as in your examples. I was assuming that you'd be able to write a transaction that transfers their assets to some other account just using the system program, token program, metaplex etc, and have them sign it and a separate fee payer sign it. But either way this isn't stuff that Phantom etc. is going to do for the user, presumably everything in that UI that lets the user use their assets is going to be broken.
    – Callum M
    Jul 19 at 20:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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