The PDA is a unique address deterministically generated by the findProgramAddressSync
function, using:
seed
encoded as UTF-8).wallet!.publicKey.toBytes()
).program.programId
), which is the address of the example program on the blockchain.How can we connect storage account
to program account
?
The program identifies the myAccount storage account using the Program Derived Address (PDA).
The Solana program (example
) is designed to recognize the PDA as the address of the Counter
storage account. The PDA is passed to the program in the accounts object during transactions.
Solana’s runtime ensures that only the program with the matching program ID can modify the data in accounts derived from its PDAs, providing security and ownership guarantees.
Check in program account source code to avoid creating multiple storage account for one wallet:
use anchor_lang::prelude::*;
#[program]
pub mod example {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
// Check if the account is already initialized
if counter.count != 0 || counter.to_account_info().data_len() > 0 {
return Err(ProgramError::AccountAlreadyInitialized.into());
}
counter.authority = ctx.accounts.payer.key();
counter.count = 0;
msg!("Counter account created! Current count: {}", counter.count);
Ok(())
}
}
After adding PDA to example
program, we have:
use anchor_lang::prelude::*;
declare_id!("2ZhxsERLkcxYuuUnHWA9K7btyzT4SyWAAcr1XZuAHaRc");
#[program]
pub mod example {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.authority = ctx.accounts.payer.key();
counter.count = 0;
msg!("Counter account created! Current count: {}", counter.count);
Ok(())
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
msg!("Previous counter: {}", counter.count);
// Optional: Validate that the signer is the authority
if ctx.accounts.authority.key() != counter.authority {
return Err(ProgramError::InvalidAccountData.into());
}
counter.count += 1;
msg!("Counter incremented! Current count: {}", counter.count);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub payer: Signer<'info>,
#[account(
init,
payer = payer,
space = 8 + 8 + 32, // Discriminator (8) + count (8) + authority (32)
seeds = [b"counter", payer.key().as_ref()],
bump
)]
pub counter: Account<'info, Counter>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(
mut,
seeds = [b"counter", authority.key().as_ref()],
bump,
has_one = authority
)]
pub counter: Account<'info, Counter>,
#[account(mut)]
pub authority: Signer<'info>,
}
#[account]
pub struct Counter {
pub count: u64,
pub authority: Pubkey,
}