Mutation

EVM

contract Counter {
  mapping(address user => uint256 count) public counter;
  
  function increment(address to, uint256 amount) external {
    counter[to] += amount;
  }
}

Solana

First time

The flag init or init_if_needed is required to initialize the Counter account.

Notes on some terminologies:

  • seeds - It is used to derive the address (Program Derived Address). It can be static or dynamic and it can contain multiple elements

  • seeds::program - It is used to derive the address for other programs

  • bump - Bump seed is a provided value that ensures the account's address is off the Ed25519 curve. An address that's off the curve does not have a corresponding private key

  • space - Each account occupies some space and it tells Solana how much space is needed. There is always an extra 8 bytes for Anchor Discriminator. This post explains it well.

#[account]
pub struct Counter {
  pub user: Pubkey,
  pub count: u64,
}

#[derive(Accounts)]
pub struct Increment {
  #[account(init, seeds = [b"user", user.key()], bump, space = 8 + 32 + 8)
  pub counter: Account<'info, Counter>,
  
  pub user: Signer<'info>,
}

pub fn increment(ctx: Context<Increment>, amount: u64) -> Result<()> {
  ctx.accounts.counter = ctx.accounts.counter.checked_add(amount).unwrap();
  Ok(())
}

Not the first time

The flag mut is required to let Solana know that the account is mutable. The program will fail silently if the flag is not present!

#[account]
pub struct Counter {
  pub user: Pubkey,
  pub count: u64,
}

#[derive(Accounts)]
pub struct Increment {
  #[account(mut, seeds = [b"user", user.key()])
  pub counter: Account<'info, Counter>,
  
  pub user: Signer<'info>,
}

pub fn increment(ctx: Context<Increment>, amount: u64) -> Result<()> {
  ctx.accounts.counter = ctx.accounts.counter.checked_add(amount).unwrap();
  Ok(())
}

Last updated