Web3 & Blockchain/Solana/Anchor Programs

Anchor Programs

Anchor is the standard framework for writing Solana programs. It handles the boilerplate of account validation, serialization, and instruction routing so you can focus on business logic.


Install

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install Solana CLI
sh -c "$(curl -sSfL https://release.solana.com/stable/install)"

# Install Anchor CLI
cargo install --git https://github.com/coral-xyz/anchor avm --locked
avm install latest
avm use latest

Create a New Program

anchor init my-program
cd my-program
anchor build
anchor test

Basic Program Structure

use anchor_lang::prelude::*;

declare_id!("YourProgramId11111111111111111111111111111111");

#[program]
pub mod my_program {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, initial_value: u64) -> Result<()> {
        let account = &mut ctx.accounts.my_account;
        account.value = initial_value;
        account.owner = ctx.accounts.user.key();
        msg!("Initialized with value: {}", initial_value);
        Ok(())
    }

    pub fn update(ctx: Context<Update>, new_value: u64) -> Result<()> {
        let account = &mut ctx.accounts.my_account;
        require!(
            account.owner == ctx.accounts.user.key(),
            MyError::Unauthorized
        );
        account.value = new_value;
        Ok(())
    }
}

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

#[derive(Accounts)]
pub struct Update<'info> {
    #[account(mut)]
    pub my_account: Account<'info, MyAccount>,
    pub user: Signer<'info>,
}

#[account]
#[derive(InitSpace)]
pub struct MyAccount {
    pub value: u64,
    pub owner: Pubkey,
}

#[error_code]
pub enum MyError {
    #[msg("You are not authorized to update this account")]
    Unauthorized,
}

Call from Frontend (TypeScript)

Anchor generates a TypeScript client from your program IDL.

import { Program, AnchorProvider, web3, BN } from "@coral-xyz/anchor";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import IDL from "./idl/my_program.json";

const PROGRAM_ID = new web3.PublicKey("YourProgramId...");

async function initializeAccount(initialValue: number) {
  const { connection } = useConnection();
  const wallet = useWallet();

  const provider = new AnchorProvider(connection, wallet, {});
  const program = new Program(IDL, provider);

  // Derive the account PDA (Program Derived Address)
  const [myAccount] = web3.PublicKey.findProgramAddressSync(
    [Buffer.from("my-account"), wallet.publicKey!.toBuffer()],
    PROGRAM_ID
  );

  await program.methods
    .initialize(new BN(initialValue))
    .accounts({
      myAccount,
      user: wallet.publicKey,
      systemProgram: web3.SystemProgram.programId,
    })
    .rpc();
}

Program Derived Addresses (PDAs)

PDAs are deterministic addresses derived from seeds. They are owned by the program and do not have a private key — only the program can sign for them.

// In the program
#[account(
    seeds = [b"vault", user.key().as_ref()],
    bump,
)]
pub vault: Account<'info, Vault>,
// In the frontend
const [vault, bump] = web3.PublicKey.findProgramAddressSync(
  [Buffer.from("vault"), userPublicKey.toBuffer()],
  PROGRAM_ID
);

SPL Token in Anchor

use anchor_spl::token::{self, Token, TokenAccount, Transfer};

pub fn transfer_tokens(ctx: Context<TransferTokens>, amount: u64) -> Result<()> {
    let cpi_accounts = Transfer {
        from: ctx.accounts.from.to_account_info(),
        to: ctx.accounts.to.to_account_info(),
        authority: ctx.accounts.authority.to_account_info(),
    };
    let cpi_program = ctx.accounts.token_program.to_account_info();
    token::transfer(CpiContext::new(cpi_program, cpi_accounts), amount)?;
    Ok(())
}

Last updated: September 2026.

Last updated · September 2026