Building on Solana Anchor Framework.

Shivank KapurShivank Kapur
5 min read

Introduction

The Solana blockchain is widely known for its speed, scalability, and minimal transaction fees, which make it a popular choice for decentralized applications (dApps). However, developing on Solana can be challenging, especially for developers unfamiliar with Rust, the language used to write smart contracts (also known as programs) on Solana. This is where the Anchor Framework comes into play, providing a streamlined, developer-friendly environment for building Solana programs.

Anchor is an open-source framework that abstracts much of the complexity involved in Solana development. It provides tools, libraries, and a common set of conventions, making Solana programming simpler, more manageable, and faster. In this article, we’ll dive deep into the Anchor Framework, exploring its main components, how to set up an Anchor project, and common patterns used in development.

What is the Solana Anchor Framework?

Anchor is a Rust-based framework for building Solana programs. It simplifies Solana development by providing a set of tools and a standardized project structure, reducing the boilerplate code typically required for interacting with Solana’s runtime. Anchor comes with several key features, including:

  1. Declarative Macros: Anchor leverages Rust macros to automate tasks, such as account validation and serialization, which would otherwise require a lot of code.

  2. IDL (Interface Definition Language): Anchor generates an IDL for each program, defining the program’s instructions and the types of data it interacts with, making it easy for frontend applications to interact with Solana programs.

  3. TypeScript Support: Anchor includes a TypeScript client library, allowing developers to interact with their Solana programs from JavaScript and TypeScript environments.

  4. Testing Utilities: Anchor’s test suite allows you to write Rust-based tests and simulates program interactions, making it easy to test and debug programs locally.

  5. Security Improvements: Anchor automates many best practices, reducing the potential for bugs and security vulnerabilities.

Setting Up a Solana Anchor Project

To start with the Anchor Framework, you'll need to have Rust, Solana, and Anchor installed on your machine.

  1. Install Rust: If you haven't installed Rust yet, you can get it by running -

     curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. Install Solana CLI: Download and install the Solana CLI tools, which you'll need to interact with the Solana blockchain.

     sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
    
  3. Install Anchor: Use Cargo (Rust's package manager) to install the Anchor CLI.

     cargo install --git https://github.com/coral-xyz/anchor anchor-cli --locked
    

After you’ve installed these tools, you can create a new Anchor project with the following command:

anchor init my_anchor_project

This command generates a new project directory with a default structure that includes folders and files to manage your Solana program’s source code, configuration, and test files.

Project Structure Overview

Anchor projects follow a standard structure:

  • programs: This folder contains the Rust source code for the Solana program.

  • migrations: Files to manage database and account migrations.

  • tests: Contains tests written in TypeScript, allowing you to simulate interactions with the program.

  • Anchor.toml: The configuration file for the Anchor project.

  • target: Directory where the compiled binaries are stored.

Writing Your First Program with Anchor

Let’s walk through a simple program using the Anchor Framework. In this example, we’ll create a "Counter" program where users can initialize a counter and increment it.

  1. Define the Program: Start by navigating to the program’s directory and opening the Rust file generated for your program (e.g., programs/my_anchor_project/src/lib.rs).

  2. Create the Counter State Struct: The counter program will require a custom data structure to store the counter’s value.

  3. Define Instructions: Anchor allows you to define functions as entry points for your program. In this case, we’ll add initialize and increment functions.

Here’s what the code might look like:

use anchor_lang::prelude::*;

declare_id!("YourProgramIDHere");

#[program]
mod counter {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
        let counter = &mut ctx.accounts.counter;
        counter.value = 0;
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> ProgramResult {
        let counter = &mut ctx.accounts.counter;
        counter.value += 1;
        Ok(())
    }
}

#[account]
pub struct Counter {
    pub value: u64,
}

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

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}

Code Explanation

  • #[program] Module: This module contains the logic for the initialize and increment functions. Each function is an instruction that can be called by users.

  • Accounts:

    • Initialize Context: The Initialize context defines the accounts needed to initialize the counter. The #[account(init, payer = user, space = 8 + 8)] attribute tells Anchor to allocate space for the Counter account (8 bytes for the Solana account header and 8 bytes for the u64 value).

    • Increment Context: The Increment context allows a user to increment the value in an existing Counter account.

  • Counter Account Struct: The Counter struct stores the counter’s state. The #[account] attribute makes it a persistent account on-chain.

Building and Deploying the Program

After writing your code, you can build and deploy your program to a local Solana cluster or a remote testnet.

  1. Build the Program:

     anchor build
    
  2. Deploy the Program:

     anchor deploy
    

The deployment will output a program ID, which you should update in the declare_id!() macro at the top of your Rust code.

Interacting with the Program

Once deployed, you can interact with your program using Anchor’s TypeScript client. In the tests folder, create a test file (e.g., counter_test.ts) with the following content:

import * as anchor from "@project-serum/anchor";
import { Program } from "@project-serum/anchor";
import { Counter } from "../target/types/counter";

describe("counter", () => {
  const provider = anchor.AnchorProvider.env();
  anchor.setProvider(provider);

  const program = anchor.workspace.Counter as Program<Counter>;

  it("Initializes the counter", async () => {
    const counter = anchor.web3.Keypair.generate();
    await program.methods
      .initialize()
      .accounts({
        counter: counter.publicKey,
        user: provider.wallet.publicKey,
        systemProgram: anchor.web3.SystemProgram.programId,
      })
      .signers([counter])
      .rpc();

    const counterAccount = await program.account.counter.fetch(counter.publicKey);
    console.log("Counter initialized to:", counterAccount.value);
  });

  it("Increments the counter", async () => {
    const counter = anchor.web3.Keypair.generate();
    await program.methods.increment().accounts({
      counter: counter.publicKey,
    }).rpc();

    const counterAccount = await program.account.counter.fetch(counter.publicKey);
    console.log("Counter incremented to:", counterAccount.value);
  });
});
10
Subscribe to my newsletter

Read articles from Shivank Kapur directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shivank Kapur
Shivank Kapur

I'm a FullStack Developer currently working with Technologies like MERN Stack, BlockChain, GraphQL, Next.js, LLMs, and a plethora of other cutting-edge tools. I'm working as a Developer Relations Engineering intern at Router Protocol and also as a Contributor at SuperteamDAO. My journey also encompasses past experiences at Push Protocol, where I orchestrated seamless community management strategies. I help Communities by Bridging the Gap between Developers and Clients. Crafting, launching, and meticulously documenting products fuel my passion, infusing every endeavor with purpose and precision. Beyond the binary, I find solace in the pages of self-help and spirituality, honing both mind and spirit with each turn of the page. phewww... I love a cup of coffee ☕ while writing code. So let's connect and have a meet over something you wanna discuss. I'll be more than happy to have it. Drop me a line at shivankkapur2004@gmail.com