# Table of Contents - [Introduction](#introduction) - [Installation](#installation) - [Anchor Framework Basics](#anchor-framework-basics) - [Local Development](#local-development) - [Quickstart](#quickstart) - [Solana Playground](#solana-playground) - [Program Structure](#program-structure) - [Program IDL File](#program-idl-file) - [Program Derived Address](#program-derived-address) - [Cross Program Invocation](#cross-program-invocation) - [Clients](#clients) - [TypeScript](#typescript) - [Dependency Free Composability](#dependency-free-composability) - [Rust](#rust) - [Zero Copy](#zero-copy) - [Testing](#testing) - [Features](#features) - [Token Integration with Anchor](#token-integration-with-anchor) - [Extensions](#extensions) - [Anchor References](#anchor-references) - [Custom Errors](#custom-errors) - [Emit Events](#emit-events) - [Mollusk](#mollusk) - [Anchor.toml Configuration](#anchor-toml-configuration) - [Anchor Version Manager](#anchor-version-manager) - [Account Types](#account-types) - [LiteSVM](#litesvm) - [Verifiable Builds](#verifiable-builds) - [Anchor CLI](#anchor-cli) - [Sealevel Attacks](#sealevel-attacks) - [Account Space](#account-space) - [Rust to JS Type Conversion](#rust-to-js-type-conversion) - [Contribution Guide](#contribution-guide) - [Example Programs](#example-programs) - [SPL Token Basics](#spl-token-basics) - [Account Constraints](#account-constraints) - [Changelog](#changelog) - [Create a Token Mint](#create-a-token-mint) - [0.31.1](#0-31-1) - [Create a Token Account](#create-a-token-account) - [Mint Tokens](#mint-tokens) - [Transfer Tokens](#transfer-tokens) - [0.29.0](#0-29-0) - [0.30.0](#0-30-0) - [0.31.0](#0-31-0) - [0.30.1](#0-30-1) --- # Introduction Introduction ============ Anchor is a development framework for building secure Solana programs (smart contracts) Anchor is the leading development framework for building Solana programs (smart contracts) and simplifies the process of writing, testing, deploying, and interacting with Solana programs. The Anchor framework helps developers build production-ready applications faster while reducing potential vulnerabilities through built-in security features. [Where to start?](https://www.anchor-lang.com/docs#where-to-start) ------------------------------------------------------------------- [### Installation\ \ Step-by-step guide to install Anchor framework. Set up your local development environment.](https://www.anchor-lang.com/docs/installation) [### Quickstart\ \ Quickstart guide to start building Solana programs with Anchor. Start building directly in your browser. No installation required.](https://www.anchor-lang.com/docs/quickstart/solpg) ### On this page [Where to start?](https://www.anchor-lang.com/docs#where-to-start) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/index.mdx) --- # Installation Installation ============ Learn how to install Rust, the Solana CLI, and Anchor Framework on Windows (WSL), Linux, or Mac. This section covers the steps to set up your local environment for Solana development. [Quick Installation](https://www.anchor-lang.com/docs/installation#quick-installation) --------------------------------------------------------------------------------------- On Mac and Linux, run this single command to install all dependencies. Terminal curl --proto '=https' --tlsv1.2 -sSfL https://solana-install.solana.workers.dev | bash Windows Users: You must first install WSL (see [Install Dependencies](https://www.anchor-lang.com/docs/installation#install-dependencies) ). Then run the command above in the Ubuntu (Linux) terminal. After installation, you should see output similar to the following: Installed Versions: Rust: rustc 1.85.0 (4d91de4e4 2025-02-17) Solana CLI: solana-cli 2.1.15 (src:53545685; feat:3271415109, client:Agave) Anchor CLI: anchor-cli 0.31.1 Node.js: v23.9.0 Yarn: 1.22.1 Installation complete. Please restart your terminal to apply all changes. If the quick installation command above doesn't work, please refer to the [Install Dependencies](https://www.anchor-lang.com/docs/installation#install-dependencies) section below for instructions to install each dependency individually. If the quick install command runs successfully, skip to the [Solana CLI Basics](https://www.anchor-lang.com/docs/installation#solana-cli-basics) and [Anchor CLI Basics](https://www.anchor-lang.com/docs/installation#anchor-cli-basics) sections below. [Install Dependencies](https://www.anchor-lang.com/docs/installation#install-dependencies) ------------------------------------------------------------------------------------------- The instructions below will guide you through installing each dependency individually. * Windows users must first install WSL (Windows subsystem for Linux) and then install the dependencies specified in the Linux section below. * Linux users should first install the dependencies specified in the Linux section below. * Mac users should start with the Rust installation instructions below. ### Windows Subsystem for Linux (WSL) ### Linux ### [Install Rust](https://www.anchor-lang.com/docs/installation#install-rust) Solana programs are written in the [Rust programming language](https://www.rust-lang.org/) . The recommended installation method for Rust is [rustup](https://www.rust-lang.org/tools/install) . Run the following command to install Rust: Terminal curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y You should see the following message after the installation completes: ### Successful Rust Install Message Run the following command to reload your PATH environment variable to include Cargo's bin directory: Terminal . "$HOME/.cargo/env" To verify that the installation was successful, check the Rust version: Terminal rustc --version You should see output similar to the following: rustc 1.84.1 (e71f9a9a9 2025-01-27) ### [Install the Solana CLI](https://www.anchor-lang.com/docs/installation#install-the-solana-cli) The Solana CLI provides all the tools required to build and deploy Solana programs. Install the Solana CLI tool suite using the official install command: Terminal sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" You can replace `stable` with the release tag matching the software version of your desired release (i.e. `v2.0.3`), or use one of the three symbolic channel names: `stable`, `beta`, or `edge`. If it is your first time installing the Solana CLI, you may see the following message prompting you to add a `PATH` environment variable: Close and reopen your terminal to apply the PATH changes or run the following in your existing shell: export PATH="/Users/test/.local/share/solana/install/active_release/bin:$PATH" LinuxMac If you are using a Linux or WSL terminal, you can add the `PATH` environment variable to your shell configuration file by running the command logged from the installation or by restarting your terminal. Terminal export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH" To verify that the installation was successful, check the Solana CLI version: Terminal solana --version You should see output similar to the following: solana-cli 2.0.26 (src:3dccb3e7; feat:607245837, client:Agave) You can view all available versions on the [Agave Github repo](https://github.com/anza-xyz/agave/releases) . Agave is the validator client from [Anza](https://www.anza.xyz/) , formerly known as Solana Labs validator client. To later update the Solana CLI to the latest version, you can use the following command: Terminal agave-install update ### [Install Anchor CLI](https://www.anchor-lang.com/docs/installation#install-anchor-cli) [Anchor](https://www.anchor-lang.com/) is a framework for developing Solana programs. The Anchor framework leverages Rust macros to simplify the process of writing Solana programs. There are two ways to install the Anchor CLI and tooling: 1. Anchor Version Manager (AVM) - Recommended installation method 2. Without AVM - Install directly from GitHub AVMWithout AVM The Anchor version manager (AVM) allows you to install and manage different Anchor versions on your system and easily update Anchor versions in the future. Install AVM with the following command: Terminal cargo install --git https://github.com/coral-xyz/anchor avm --force Check that AVM was installed successfully: Terminal avm --version Install the latest version of Anchor CLI using AVM: Terminal avm install latest avm use latest Alternatively, you can install a specific version of Anchor CLI by specifying the version number: Terminal avm install 0.31.1 avm use 0.31.1 Don't forget to run the `avm use` command to declare which Anchor CLI version should be used on your system. * If you installed the `latest` version, run `avm use latest`. * If you installed the version `0.31.1`, run `avm use 0.31.1`. To verify that the installation was successful, check the Anchor CLI version: Terminal anchor --version You should see output similar to the following: anchor-cli 0.31.1 When installing the Anchor CLI on Linux or WSL, you may encounter this error: error: could not exec the linker cc = note: Permission denied (os error 13) If you see this error message, follow these steps: 1. Install the dependencies listed in the [Linux](https://www.anchor-lang.com/docs/installation#install-dependencies) section at the top of this page. 2. Retry installing the Anchor CLI. #### [Node.js and Yarn](https://www.anchor-lang.com/docs/installation#nodejs-and-yarn) Node.js and Yarn are required to run the default Anchor project test file (TypeScript) created with the `anchor init` command. (Rust test template is also available using `anchor init --test-template rust`) ### Node Installation ### Yarn Installation When running `anchor build`, if you encounter the following errors: ### error: not a directory ### lock file version 4 requires \`-Znext-lockfile-bump After applying the solution above, attempt to run `anchor build` again. When running `anchor test` after creating a new Anchor project on Linux or WSL, you may encounter the following errors if Node.js or Yarn are not installed: Permission denied (os error 13) No such file or directory (os error 2) [Solana CLI Basics](https://www.anchor-lang.com/docs/installation#solana-cli-basics) ------------------------------------------------------------------------------------- This section will walk through some common Solana CLI commands to get you started. ### [Solana Config](https://www.anchor-lang.com/docs/installation#solana-config) To see your current config: solana config get You should see output similar to the following: Config File: /Users/test/.config/solana/cli/config.yml RPC URL: https://api.mainnet-beta.solana.com WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed) Keypair Path: /Users/test/.config/solana/id.json Commitment: confirmed The RPC URL and Websocket URL specific the Solana cluster the CLI will make requests to. By default this will be mainnet-beta. You can update the Solana CLI cluster using the following commands: solana config set --url mainnet-beta solana config set --url devnet solana config set --url localhost solana config set --url testnet You can also use the following short options: solana config set -um # For mainnet-beta solana config set -ud # For devnet solana config set -ul # For localhost solana config set -ut # For testnet The Keypair Path specifies the location of the default wallet used by the Solana CLI (to pay transaction fees and deploy programs). The default path is `~/.config/solana/id.json`. The next step walks through how to generate a keypair at the default location. ### [Create Wallet](https://www.anchor-lang.com/docs/installation#create-wallet) To interact with the Solana network using the Solana CLI, you need a Solana wallet funded with SOL. To generate a keypair at the default Keypair Path, run the following command: solana-keygen new You should see output similar to the following: Generating a new keypair For added security, enter a BIP39 passphrase NOTE! This passphrase improves security of the recovery seed phrae NOT the keypair file itself, which is stored as insecure plain text BIP39 Passphrase (empty for none): Wrote new keypair to /Users/test/.config/solana/id.json =========================================================================== pubkey: 8dBTPrjnkXyuQK3KDt9wrZBfizEZijmmUQXVHpFbVwGT =========================================================================== Save this seed phrase and your BIP39 passphrase to recover your new keypair: cream bleak tortoise ocean nasty game gift forget fancy salon mimic amazing =========================================================================== If you already have a file system wallet saved at the default location, this command will **NOT** override it unless you explicitly force override using the `--force` flag. Once a keypair is generated, you can get the address (public key) of the keypair with the following command: solana address ### [Airdrop SOL](https://www.anchor-lang.com/docs/installation#airdrop-sol) Once you've set up your local wallet, request an airdrop of SOL to fund your wallet. You need SOL to pay for transaction fees and to deploy programs. Set your cluster to the devnet: solana config set -ud Then request an airdrop of devnet SOL: solana airdrop 2 To check your wallet's SOL balance, run the following command: solana balance The `solana airdrop` command is currently limited to 5 SOL per request on devnet. Errors are likely due to rate limits. Alternatively, you can get devnet SOL using the [Solana Web Faucet](https://faucet.solana.com/) . ### [Run Local Validator](https://www.anchor-lang.com/docs/installation#run-local-validator) The Solana CLI comes with the [test validator](https://docs.solanalabs.com/cli/examples/test-validator) built-in. Running a local validator will allow you to deploy and test your programs locally. In a separate terminal, run the following command to start a local validator: solana-test-validator Make sure to update the Solana CLI config to localhost before commands. solana config set -ul [Anchor CLI Basics](https://www.anchor-lang.com/docs/installation#anchor-cli-basics) ------------------------------------------------------------------------------------- This section will walk through some common Anchor CLI commands to get you started. For more information on the Anchor CLI, see the [Anchor documentation](https://www.anchor-lang.com/docs) . ### [Initialize Project](https://www.anchor-lang.com/docs/installation#initialize-project) To create a new Anchor project, run the following command: Terminal anchor init For example, to create a project called `my-project`, run: Terminal anchor init my-project This command creates a new directory with the project name and initializes a new Anchor project with a basic Rust program and TypeScript test template. Navigate to the project directory: Terminal cd See the Anchor project's [file structure](https://www.anchor-lang.com/docs/quickstart/local#project-file-structure) . ### [Build Program](https://www.anchor-lang.com/docs/installation#build-program) To build your project, run the following command: Terminal anchor build The compiled program can be found in the `/target/deploy` directory. ### [Deploy Program](https://www.anchor-lang.com/docs/installation#deploy-program) To deploy your project, run the following command: Terminal anchor deploy This command will deploy your program to the `cluster` specified in the [`Anchor.toml`](https://www.anchor-lang.com/docs/references/anchor-toml) file. ### [Test Program](https://www.anchor-lang.com/docs/installation#test-program) To test your project, run the following command: Terminal anchor test This command builds, deploys, and runs the tests for your project. When using `localnet` as the `cluster` in `Anchor.toml`, Anchor automatically starts a local validator, deploys your program, runs tests, and then stops the validator. [Shell Completions](https://www.anchor-lang.com/docs/installation#shell-completions) ------------------------------------------------------------------------------------- Shell completions can be generated for [`bash`](https://www.anchor-lang.com/docs/installation#bash) , [`fish`](https://www.anchor-lang.com/docs/installation#fish) and [`zsh`](https://www.anchor-lang.com/docs/installation#zsh) . ### [Bash](https://www.anchor-lang.com/docs/installation#bash) Terminal mkdir -p $HOME/.local/share/bash-completion/completions anchor completions bash > $HOME/.local/share/bash-completion/completions/anchor avm completions bash > $HOME/.local/share/bash-completion/completions/avm exec bash ### [Fish](https://www.anchor-lang.com/docs/installation#fish) Terminal mkdir -p $HOME/.config/fish/completions anchor completions fish > $HOME/.config/fish/completions/anchor.fish avm completions fish > $HOME/.config/fish/completions/avm.fish source $HOME/.config/fish/config.fish ### [Zsh](https://www.anchor-lang.com/docs/installation#zsh) First ensure the following is in your `.zshrc` file. If using `oh-my-zsh` this step can be skipped. Terminal autoload -U compinit compinit -i Next run: Terminal anchor completions zsh | sudo tee /usr/local/share/zsh/site-functions/_anchor avm completions zsh | sudo tee /usr/local/share/zsh/site-functions/_avm exec zsh [Next\ \ Quickstart](https://www.anchor-lang.com/docs/quickstart) ### On this page [Quick Installation](https://www.anchor-lang.com/docs/installation#quick-installation) [Install Dependencies](https://www.anchor-lang.com/docs/installation#install-dependencies) [Install Rust](https://www.anchor-lang.com/docs/installation#install-rust) [Install the Solana CLI](https://www.anchor-lang.com/docs/installation#install-the-solana-cli) [Install Anchor CLI](https://www.anchor-lang.com/docs/installation#install-anchor-cli) [Solana CLI Basics](https://www.anchor-lang.com/docs/installation#solana-cli-basics) [Solana Config](https://www.anchor-lang.com/docs/installation#solana-config) [Create Wallet](https://www.anchor-lang.com/docs/installation#create-wallet) [Airdrop SOL](https://www.anchor-lang.com/docs/installation#airdrop-sol) [Run Local Validator](https://www.anchor-lang.com/docs/installation#run-local-validator) [Anchor CLI Basics](https://www.anchor-lang.com/docs/installation#anchor-cli-basics) [Initialize Project](https://www.anchor-lang.com/docs/installation#initialize-project) [Build Program](https://www.anchor-lang.com/docs/installation#build-program) [Deploy Program](https://www.anchor-lang.com/docs/installation#deploy-program) [Test Program](https://www.anchor-lang.com/docs/installation#test-program) [Shell Completions](https://www.anchor-lang.com/docs/installation#shell-completions) [Bash](https://www.anchor-lang.com/docs/installation#bash) [Fish](https://www.anchor-lang.com/docs/installation#fish) [Zsh](https://www.anchor-lang.com/docs/installation#zsh) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/installation.mdx) --- # Anchor Framework Basics Anchor Framework Basics ======================= Learn how to use the Anchor framework to build secure Solana programs. Before diving into Anchor, it's recommended to have a basic understanding of [Solana's core concepts](https://solana.com/docs/core) . [### Program Structure\ \ Learn about the structure of Anchor programs, including key macros and their roles in simplifying Solana program development](https://www.anchor-lang.com/docs/basics/program-structure) [### Program IDL File\ \ Learn about the Interface Description Language (IDL) file in Anchor, its purpose, benefits, and how it simplifies program-client interactions](https://www.anchor-lang.com/docs/basics/idl) [### Program Derived Address\ \ Learn how to use Program Derived Addresses (PDAs) in Anchor programs to create deterministic account addresses.](https://www.anchor-lang.com/docs/basics/pda) [### Cross Program Invocation\ \ Learn how to implement Cross Program Invocations (CPIs) in Anchor programs to enable composability between different Solana programs.](https://www.anchor-lang.com/docs/basics/cpi) [Previous\ \ Local Development](https://www.anchor-lang.com/docs/quickstart/local) [Next\ \ Program Structure](https://www.anchor-lang.com/docs/basics/program-structure) ### On this page No Headings [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/basics/index.mdx) --- # Local Development [Quickstart](https://www.anchor-lang.com/docs/quickstart) Local Development ================= Learn how to build Solana programs using the Anchor framework on your local machine. The Anchor framework is a tool that simplifies the process of building Solana programs. Whether you're new to blockchain development or an experienced programmer, Anchor simplifies the process of writing, testing, and deploying Solana programs. In this section, we'll walk through: * Creating a new Anchor project * Building and testing your program * Deploying to Solana clusters * Understanding the project file structure [Prerequisites](https://www.anchor-lang.com/docs/quickstart/local#prerequisites) --------------------------------------------------------------------------------- For detailed installation instructions, visit the [installation](https://www.anchor-lang.com/docs/installation) page. Before you begin, ensure you have the following installed: * Rust: The programming language for building Solana programs. * Solana CLI: Command-line tool for Solana development. * Anchor CLI: Command-line tool for the Anchor framework. To verify Anchor CLI installation, open your terminal and run: anchor --version Expected output: anchor-cli 0.31.1 [Getting Started](https://www.anchor-lang.com/docs/quickstart/local#getting-started) ------------------------------------------------------------------------------------- This section covers the basic steps to create, build, and test your first local Anchor program. ### [Create a new Project](https://www.anchor-lang.com/docs/quickstart/local#create-a-new-project) To start a new project, use the `anchor init` command followed by your project's name. This command creates a new directory with the specified name and sets up a default program and test file. anchor init my-project Navigate to the new project directory and open it in your code editor. cd my-project The default Anchor program is located at `/programs/my-project/src/lib.rs`. ### Default Program The default Typescript test file is located at `/tests/my-project.ts`. ### Default Test File If you prefer Rust for testing, initialize your project with the `--test-template rust` ([Anchor Rust client](https://www.anchor-lang.com/docs/clients/rust) ) or `--test-template mollusk` ([Mollusk test library](https://www.anchor-lang.com/docs/testing/mollusk) ) flag. anchor init --test-template rust my-program The Rust test file will be at `/tests/src/test_initialize.rs`. ### Rust Test File ### [Build the Program](https://www.anchor-lang.com/docs/quickstart/local#build-the-program) Build the program by running `anchor build`. anchor build The compiled program will be at `/target/deploy/my_project.so`. The content of this file is what gets stored on the Solana network (as an executable account) when you deploy your program. ### [Test the Program](https://www.anchor-lang.com/docs/quickstart/local#test-the-program) To test the program, run `anchor test`. anchor test By default, the `Anchor.toml` config file specifies the `localnet` cluster. When developing on `localnet`, `anchor test` will automatically: 1. Start a local Solana validator 2. Build and deploy your program to the local cluster 3. Run the tests in the `tests` folder 4. Stop the local Solana validator Alternatively, you can manually start a local Solana validator and run tests against it. This is useful if you want to keep the validator running while you iterate on your program. It allows you to inspect accounts and transaction logs on the [Solana Explorer](https://explorer.solana.com/?cluster=custom) while developing locally. Open a new terminal and start a local Solana validator by running the `solana-test-validator` command. solana-test-validator In a separate terminal, run the tests against the local cluster. Use the `--skip-local-validator` flag to skip starting the local validator since it's already running. anchor test --skip-local-validator ### [Deploy to Devnet](https://www.anchor-lang.com/docs/quickstart/local#deploy-to-devnet) By default, the `Anchor.toml` config file in an Anchor project specifies the localnet cluster. [toolchain] [features] resolution = true skip-lint = false [programs.localnet] my_program = "3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg" [registry] url = "https://api.apr.dev" [provider] cluster = "Localnet" wallet = "~/.config/solana/id.json" [scripts] test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" To deploy your program to devnet, change the `cluster` value to `Devnet`. Note that deploying to devnet requires your wallet to have enough SOL to cover deployment cost. You can get devnet SOL using the [Web Faucet](https://faucet.solana.com/) . -cluster = "Localnet" +cluster = "Devnet" [provider] cluster = "Devnet" wallet = "~/.config/solana/id.json" Now when you run `anchor deploy`, your program will be deployed to the devnet cluster. The `anchor test` command will also use the cluster specified in the `Anchor.toml` file. anchor deploy To deploy to mainnet, simply update the `Anchor.toml` file to specify the mainnet cluster. [provider] cluster = "Mainnet" wallet = "~/.config/solana/id.json" ### [Update the Program](https://www.anchor-lang.com/docs/quickstart/local#update-the-program) Solana programs can be updated by redeploying the program to the same program ID. To update a program, simply make changes to your program's code and run the `anchor build` command to generated an updated `.so` file. anchor build Then run the `anchor deploy` command to redeploy the updated program. anchor deploy ### [Close the Program](https://www.anchor-lang.com/docs/quickstart/local#close-the-program) To reclaim the SOL allocated to a program account, you can close your Solana program. To close a program, use the `solana program close ` command. For example: solana program close 3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg --bypass-warning Note that once a program is closed, the program ID cannot be reused to deploy a new program. [Project File Structure](https://www.anchor-lang.com/docs/quickstart/local#project-file-structure) --------------------------------------------------------------------------------------------------- Below is an overview of default file structure in an Anchor workspace: .anchor app migrations programs \[project-name\] src lib.rs Cargo.toml Xargo.toml target deploy idl types tests \[project-name\].ts Anchor.toml Cargo.toml package.json ### [Programs Folder](https://www.anchor-lang.com/docs/quickstart/local#programs-folder) The `/programs` directory contains your project's Anchor programs. A single workspace can contain multiple programs. ### [Tests Folder](https://www.anchor-lang.com/docs/quickstart/local#tests-folder) The `/tests` directory contains test files for your project. A default test file is created for you when you create your project. ### [Target Folder](https://www.anchor-lang.com/docs/quickstart/local#target-folder) The `/target` directory contains build outputs. The main subfolders include: * `/deploy`: Contains the keypair and program binary for your programs. * `/idl`: Contains the JSON IDL for your programs. * `/types`: Contains the TypeScript type for the IDL. ### [Anchor.toml File](https://www.anchor-lang.com/docs/quickstart/local#anchortoml-file) The `Anchor.toml` file configures workspace settings for your project. ### [.anchor Folder](https://www.anchor-lang.com/docs/quickstart/local#anchor-folder) Includes a `program-logs` file that contains transaction logs from the last run of test files. ### [App Folder](https://www.anchor-lang.com/docs/quickstart/local#app-folder) The `/app` folder is an empty folder that can be optionally used for your frontend code. [Previous\ \ Solana Playground](https://www.anchor-lang.com/docs/quickstart/solpg) [Next\ \ Anchor Framework Basics](https://www.anchor-lang.com/docs/basics) ### On this page [Prerequisites](https://www.anchor-lang.com/docs/quickstart/local#prerequisites) [Getting Started](https://www.anchor-lang.com/docs/quickstart/local#getting-started) [Create a new Project](https://www.anchor-lang.com/docs/quickstart/local#create-a-new-project) [Build the Program](https://www.anchor-lang.com/docs/quickstart/local#build-the-program) [Test the Program](https://www.anchor-lang.com/docs/quickstart/local#test-the-program) [Deploy to Devnet](https://www.anchor-lang.com/docs/quickstart/local#deploy-to-devnet) [Update the Program](https://www.anchor-lang.com/docs/quickstart/local#update-the-program) [Close the Program](https://www.anchor-lang.com/docs/quickstart/local#close-the-program) [Project File Structure](https://www.anchor-lang.com/docs/quickstart/local#project-file-structure) [Programs Folder](https://www.anchor-lang.com/docs/quickstart/local#programs-folder) [Tests Folder](https://www.anchor-lang.com/docs/quickstart/local#tests-folder) [Target Folder](https://www.anchor-lang.com/docs/quickstart/local#target-folder) [Anchor.toml File](https://www.anchor-lang.com/docs/quickstart/local#anchortoml-file) [.anchor Folder](https://www.anchor-lang.com/docs/quickstart/local#anchor-folder) [App Folder](https://www.anchor-lang.com/docs/quickstart/local#app-folder) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/quickstart/local.mdx) --- # Quickstart Quickstart ========== Learn how to quickly get started with Anchor, the leading Solana smart contract development framework. [### Solana Playground\ \ Learn how to build your first Solana program using the Anchor framework directly in your browser.](https://www.anchor-lang.com/docs/quickstart/solpg) [### Local Development\ \ Learn how to build Solana programs using the Anchor framework on your local machine.](https://www.anchor-lang.com/docs/quickstart/local) [Previous\ \ Installation](https://www.anchor-lang.com/docs/installation) [Next\ \ Solana Playground](https://www.anchor-lang.com/docs/quickstart/solpg) ### On this page No Headings [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/quickstart/index.mdx) --- # Solana Playground [Quickstart](https://www.anchor-lang.com/docs/quickstart) Solana Playground ================= Learn how to build your first Solana program using the Anchor framework directly in your browser. In this section, we'll build, deploy, and test a simple Solana program using the Anchor framework. By the end, you'll have deployed your first program to the Solana blockchain! Solana Playground (Solpg) is a browser-based development environment that allows you to quickly develop, deploy, and test Solana programs! [Getting Started](https://www.anchor-lang.com/docs/quickstart/solpg#getting-started) ------------------------------------------------------------------------------------- Open a new tab in your web browser and navigate to [https://beta.solpg.io/](https://beta.solpg.io/) . ### [Create Playground Wallet](https://www.anchor-lang.com/docs/quickstart/solpg#create-playground-wallet) If you're new to Solana Playground, the first step is to create your Playground Wallet. This wallet will allow you to interact with the Solana network right from your browser. #### [Step 1. Connect to Playground](https://www.anchor-lang.com/docs/quickstart/solpg#step-1-connect-to-playground) Click the "Not connected" button at the bottom left of the screen. ![Not Connected](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpg-not-connected.d932bd10.png&w=3840&q=75) #### [Step 2. Create Your Wallet](https://www.anchor-lang.com/docs/quickstart/solpg#step-2-create-your-wallet) You'll see an option to save your wallet's keypair. Optionally, save your wallet's keypair for backup and then click "Continue". ![Create Playground Wallet](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpg-create-wallet.e6d1861e.png&w=3840&q=75) You should now see your wallet's address, SOL balance, and connected cluster (devnet by default) at the bottom of the window. ![Connected](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpg-connected.0bf12931.png&w=3840&q=75) Your Playground Wallet will be saved in your browser's local storage. Clearing your browser cache will remove your saved wallet. Some definitions you may find helpful: * _wallet address_: a public key that serves as your unique identity on the Solana blockchain. Just like an email address is used to receive emails, your wallet address is used to receive SOL. * _connection cluster_: a network of Solana nodes (computers running Solana validator client). Devnet is the cluster for developer testing. ### [Get Devnet SOL](https://www.anchor-lang.com/docs/quickstart/solpg#get-devnet-sol) Before we start building, we first need some devnet SOL. From a developer's perspective, SOL is required for two main use cases: * To create accounts on the network where we store data or deploy programs * To pay for transaction fees when we interact with the network Below are two methods to fund your wallet with devnet SOL: #### [Option 1: Using the Playground Terminal](https://www.anchor-lang.com/docs/quickstart/solpg#option-1-using-the-playground-terminal) To fund your Playground wallet with devnet SOL. In the Playground terminal, run: solana airdrop 5 #### [Option 2: Using the Devnet Faucet](https://www.anchor-lang.com/docs/quickstart/solpg#option-2-using-the-devnet-faucet) If the airdrop command doesn't work (due to rate limits or errors), you can use the [Web Faucet](https://faucet.solana.com/) . * Enter your wallet address (found at the bottom of the Playground screen) and select an amount * Click "Confirm Airdrop" to receive your devnet SOL ![Faucet Airdrop](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ffaucet-airdrop.c50ea031.gif&w=3840&q=75) ### [Create Anchor Project](https://www.anchor-lang.com/docs/quickstart/solpg#create-anchor-project) First, open [https://beta.solpg.io](https://beta.solpg.io/) in a new browser tab. * Click the "Create a new project" button on the left-side panel. * Enter a project name, select Anchor as the framework, then click the "Create" button. ![New Project](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpg-new-project.d886b6f3.gif&w=3840&q=75) You'll see a new project created with the program code in the `src/lib.rs` file. use anchor_lang::prelude::*; // This is your program's public key and it will update // automatically when you build the project. declare_id!("11111111111111111111111111111111"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); // Message will show up in the tx logs Ok(()) } } #[derive(Accounts)] pub struct Initialize<'info> { // We must specify the space in order to initialize an account. // First 8 bytes are default account discriminator, // next 8 bytes come from NewAccount.data being type u64. // (u64 = 64 bits unsigned integer = 8 bytes) #[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>, } #[account] pub struct NewAccount { data: u64 } ### Explanation ### [Build and Deploy Program](https://www.anchor-lang.com/docs/quickstart/solpg#build-and-deploy-program) To build the program, simply run `build` in the terminal. build Notice that the address in `declare_id!()` has been updated. This is your program's on-chain address. ### Output Once the program is built, run `deploy` in the terminal to deploy the program to the network (devnet by default). To deploy a program, SOL must be allocated to the on-chain account that stores the program. Before deployment, ensure you have enough SOL. You can get devnet SOL by either running `solana airdrop 5` in the Playground terminal or using the [Web Faucet](https://faucet.solana.com/) . deploy ### Output Alternatively, you can also use the `Build` and `Deploy` buttons on the left-side panel. ![Build and Deploy](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpg-build-deploy.b5c421d7.png&w=3840&q=75) Once the program is deployed, you can now invoke its instructions. ### [Test Program](https://www.anchor-lang.com/docs/quickstart/solpg#test-program) Included with the starter code is a test file found in `tests/anchor.test.ts`. This file demonstrates how to invoke the `initialize` instruction on the starter program from the client. // No imports needed: web3, anchor, pg and more are globally available describe("Test", () => { it("initialize", async () => { // Generate keypair for the new account const newAccountKp = new web3.Keypair(); // Send transaction const data = new BN(42); const txHash = await pg.program.methods .initialize(data) .accounts({ newAccount: newAccountKp.publicKey, signer: pg.wallet.publicKey, systemProgram: web3.SystemProgram.programId, }) .signers([newAccountKp]) .rpc(); console.log(`Use 'solana confirm -v ${txHash}' to see the logs`); // Confirm transaction await pg.connection.confirmTransaction(txHash); // Fetch the created account const newAccount = await pg.program.account.newAccount.fetch( newAccountKp.publicKey, ); console.log("On-chain data is:", newAccount.data.toString()); // Check whether the data on-chain is equal to local 'data' assert(data.eq(newAccount.data)); }); }); To run the test file once the program is deployed, run `test` in the terminal. test You should see an output indicating that the test passed successfully. ### Output You can also use the `Test` button on the left-side panel. ![Run Test](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpg-test.e1a16c4b.png&w=3840&q=75) You can then view the transaction logs by running the `solana confirm -v` command and specifying the transaction hash (signature) from the test output: solana confirm -v [TxHash] For example: solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc ### Output Alternatively, you can view the transaction details on [SolanaFM](https://solana.fm/) or [Solana Explorer](https://explorer.solana.com/?cluster=devnet) by searching for the transaction signature (hash). Reminder to update the cluster (network) connection on the Explorer you are using to match Solana Playground. Solana Playground's default cluster is devnet. ### [Close Program](https://www.anchor-lang.com/docs/quickstart/solpg#close-program) Lastly, the SOL allocated to the on-chain program can be fully recovered by closing the program. You can close a program by running the following command and specifying the program address found in `declare_id!()`: solana program close [ProgramID] For example: solana program close 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r ### Output ### Explanation Congratulations! You've just built and deployed your first Solana program using the Anchor framework! [Previous\ \ Quickstart](https://www.anchor-lang.com/docs/quickstart) [Next\ \ Local Development](https://www.anchor-lang.com/docs/quickstart/local) ### On this page [Getting Started](https://www.anchor-lang.com/docs/quickstart/solpg#getting-started) [Create Playground Wallet](https://www.anchor-lang.com/docs/quickstart/solpg#create-playground-wallet) [Get Devnet SOL](https://www.anchor-lang.com/docs/quickstart/solpg#get-devnet-sol) [Create Anchor Project](https://www.anchor-lang.com/docs/quickstart/solpg#create-anchor-project) [Build and Deploy Program](https://www.anchor-lang.com/docs/quickstart/solpg#build-and-deploy-program) [Test Program](https://www.anchor-lang.com/docs/quickstart/solpg#test-program) [Close Program](https://www.anchor-lang.com/docs/quickstart/solpg#close-program) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/quickstart/solpg.mdx) --- # Program Structure [The Basics](https://www.anchor-lang.com/docs/basics) Program Structure ================= Learn about the structure of Anchor programs, including key macros and their roles in simplifying Solana program development The Anchor framework uses [Rust macros](https://rust-book.cs.brown.edu/ch20-05-macros.html?highlight=macros#macros) to reduce boilerplate code and simplify the implementation of common security checks required for writing Solana programs. The main macros found in an Anchor program include: * [`declare_id`](https://www.anchor-lang.com/docs/basics/program-structure#declare_id-macro) : Specifies the program's on-chain address * [`#[program]`](https://www.anchor-lang.com/docs/basics/program-structure#program-attribute) : Specifies the module containing the program’s instruction logic * [`#[derive(Accounts)]`](https://www.anchor-lang.com/docs/basics/program-structure#deriveaccounts-macro) : Applied to structs to indicate a list of accounts required by an instruction * [`#[account]`](https://www.anchor-lang.com/docs/basics/program-structure#account-attribute) : Applied to structs to create custom account types for the program [Example Program](https://www.anchor-lang.com/docs/basics/program-structure#example-program) --------------------------------------------------------------------------------------------- Let's examine a simple program that demonstrates the usage of the macros mentioned above to understand the basic structure of an Anchor program. The program below includes a single instruction called `initialize` that creates a new account (`NewAccount`) and initializes it with a `u64` value. lib.rs use anchor_lang::prelude::*; declare_id!("11111111111111111111111111111111"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } #[account] pub struct NewAccount { data: u64, } [declare\_id! macro](https://www.anchor-lang.com/docs/basics/program-structure#declare_id-macro) ------------------------------------------------------------------------------------------------- The [`declare_id`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L537) macro specifies the on-chain address of the program, known as the program ID. You can find the implementation of the code generated by the `declare_id!` macro [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/id.rs#L37-L70) . lib.rs use anchor_lang::prelude::*; declare_id!("11111111111111111111111111111111"); By default, the program ID is the public key of the keypair generated at `/target/deploy/your_program_name.json`. To update the value of the program ID in the `declare_id` macro with the public key of the keypair in the `/target/deploy/your_program_name.json` file, run the following command: Terminal anchor keys sync The `anchor keys sync` command is useful to run when cloning a repository where the value of the program ID in a cloned repo's `declare_id` macro won't match the one generated when you run `anchor build` locally. [#\[program\] attribute](https://www.anchor-lang.com/docs/basics/program-structure#program-attribute) ------------------------------------------------------------------------------------------------------ The [`#[program]`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/lib.rs#L12) attribute annotates the module containing all the instruction handlers for your program. Each public function within this module corresponds to an instruction that can be invoked. You can find the implementation of the code generated by the `#[program]` attribute [here](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/program) . lib.rs use anchor_lang::prelude::*; declare_id!("11111111111111111111111111111111"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } #[account] pub struct NewAccount { data: u64, } ### [Instruction Context](https://www.anchor-lang.com/docs/basics/program-structure#instruction-context) Instruction handlers are functions that define the logic executed when an instruction is invoked. The first parameter of each handler is a `Context` type, where `T` is a struct implementing the [`Accounts`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/lib.rs#L108) trait and specifies the accounts the instruction requires. The [`Context`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/context.rs#L24) type provides the instruction with access to the following non-argument inputs: pub struct Context<'a, 'b, 'c, 'info, T: Bumps> { /// Currently executing program id. pub program_id: &'a Pubkey, /// Deserialized accounts. pub accounts: &'b mut T, /// Remaining accounts given but not deserialized or validated. /// Be very careful when using this directly. pub remaining_accounts: &'c [AccountInfo<'info>], /// Bump seeds found during constraint validation. This is provided as a /// convenience so that handlers don't have to recalculate bump seeds or /// pass them in as arguments. /// Type is the bumps struct generated by #[derive(Accounts)] pub bumps: T::Bumps, } The `Context` fields can be accessed in an instruction using dot notation: * `ctx.accounts`: The accounts required for the instruction * `ctx.program_id`: The program's public key (address) * `ctx.remaining_accounts`: Additional accounts not specified in the `Accounts` struct. * `ctx.bumps`: Bump seeds for any Program Derived Address (PDA) accounts specified in the `Accounts` struct Additional parameters are optional and can be included to specify arguments that must be provided when the instruction is invoked. lib.rs pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } In this example, the `Initialize` struct implements the `Accounts` trait where each field in the struct represents an account required by the `initialize` instruction. lib.rs #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } [#\[derive(Accounts)\] macro](https://www.anchor-lang.com/docs/basics/program-structure#deriveaccounts-macro) -------------------------------------------------------------------------------------------------------------- The [`#[derive(Accounts)]`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/derive/accounts/src/lib.rs#L631) macro is applied to a struct to specify the accounts that must be provided when an instruction is invoked. This macro implements the [`Accounts`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/lib.rs#L108) trait, which simplifies account validation and serialization and deserialization of account data. You can find the implementation of the code generated by the `#[derive(Accounts)]` macro [here](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/accounts) . #[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>, } Each field in the struct represents an account required by an instruction. The naming of each field is arbitrary, but it is recommended to use a descriptive name that indicates the purpose of the 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>, } ### [Account Validation](https://www.anchor-lang.com/docs/basics/program-structure#account-validation) To prevent security vulnerabilities, it's important to verify that accounts provided to an instruction are the expected accounts. Accounts are validated in Anchor programs in two ways that are generally used together: * [Account Constraints](https://www.anchor-lang.com/docs/references/account-constraints) : Constraints define additional conditions that an account must satisfy to be considered valid for the instruction. Constraints are applied using the `#[account(..)]` attribute, which is placed above a field in a struct that implements the `Accounts` trait. You can find a full list of the constraints [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/parser/accounts/constraints.rs) and implementation [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/accounts/constraints.rs) . #[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>, } * [Account Types](https://www.anchor-lang.com/docs/references/account-types) : Anchor provides various account types to help ensure that the account provided by the client matches what the program expects. You can find the implementation of the account types [here](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/accounts) . #[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>, } When an instruction in an Anchor program is invoked, the program first validates the accounts provided before executing the instruction's logic. After validation, these accounts can be accessed within the instruction using the `ctx.accounts` syntax. lib.rs use anchor_lang::prelude::*; declare_id!("11111111111111111111111111111111"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } #[account] pub struct NewAccount { data: u64, } [#\[account\] attribute](https://www.anchor-lang.com/docs/basics/program-structure#account-attribute) ------------------------------------------------------------------------------------------------------ The [`#[account]`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L97) attribute is applied to structs that define the structure of the data stored in custom accounts created by your program. #[account] pub struct NewAccount { data: u64, } This macro implements various traits [detailed here](https://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html) . The key functionalities of the `#[account]` macro include: * [Assign Program Owner](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L130-L143) : When creating an account, the program owner of the account is automatically set to the program specified in `declare_id`. * [Set Discriminator](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L111-L128) : A unique 8 byte discriminator, specific to the account type, is added as the first 8 bytes of account data during its initialization. This helps in differentiating account types and is used for account validation. * [Data Serialization and Deserialization](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L224-L270) : Account data is automatically serialized and deserialized as the account type. lib.rs use anchor_lang::prelude::*; declare_id!("11111111111111111111111111111111"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } #[account] pub struct NewAccount { data: u64, } ### [Account Discriminator](https://www.anchor-lang.com/docs/basics/program-structure#account-discriminator) An account discriminator in an Anchor program refers to an 8 byte identifier unique to each account type. You can find the implementation of the account discriminator [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L111-L128) . The discriminator is the first 8 bytes of the SHA256 hash of the string `account:`. This discriminator is stored as the first 8 bytes of account data when an account is created. When creating an account in an Anchor program, 8 bytes must be allocated for the discriminator. #[account(init, payer = signer, space = 8 + 8)] pub new_account: Account<'info, NewAccount>, The discriminator is used during the following two scenarios: * Initialization: When an account is created, the discriminator is set as the first 8 bytes of the account's data. * Deserialization: When account data is deserialized, the first 8 bytes of account data is checked against the discriminator of the expected account type. If there's a mismatch, it indicates that the client has provided an unexpected account. This mechanism serves as an account validation check in Anchor programs. [Previous\ \ Anchor Framework Basics](https://www.anchor-lang.com/docs/basics) [Next\ \ Program IDL File](https://www.anchor-lang.com/docs/basics/idl) ### On this page [Example Program](https://www.anchor-lang.com/docs/basics/program-structure#example-program) [declare\_id! macro](https://www.anchor-lang.com/docs/basics/program-structure#declare_id-macro) [#\[program\] attribute](https://www.anchor-lang.com/docs/basics/program-structure#program-attribute) [Instruction Context](https://www.anchor-lang.com/docs/basics/program-structure#instruction-context) [#\[derive(Accounts)\] macro](https://www.anchor-lang.com/docs/basics/program-structure#deriveaccounts-macro) [Account Validation](https://www.anchor-lang.com/docs/basics/program-structure#account-validation) [#\[account\] attribute](https://www.anchor-lang.com/docs/basics/program-structure#account-attribute) [Account Discriminator](https://www.anchor-lang.com/docs/basics/program-structure#account-discriminator) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/basics/program-structure.mdx) --- # Program IDL File [The Basics](https://www.anchor-lang.com/docs/basics) Program IDL File ================ Learn about the Interface Description Language (IDL) file in Anchor, its purpose, benefits, and how it simplifies program-client interactions An Interface Description Language (IDL) file for an Anchor program provides a standardized JSON file describing the program's instructions and accounts. This file simplifies the process of integrating your on-chain program with client applications. Key Benefits of the IDL: * Standardization: Provides a consistent format for describing the program's instructions and accounts * Client Generation: Used to generate client code to interact with the program The `anchor build` command generates an IDL file located at `/target/idl/.json`. The code snippets in the sections below highlight how the program, IDL, and client relate to each other. [Program Instructions](https://www.anchor-lang.com/docs/basics/idl#program-instructions) ----------------------------------------------------------------------------------------- The `instructions` array in the IDL corresponds directly to the instructions defined in your program. It specifies the required accounts and parameters for each instruction. ProgramIDLClient The program below includes an `initialize` instruction, specifying the accounts and parameters it requires. lib.rs use anchor_lang::prelude::*; declare_id!("BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } #[account] pub struct NewAccount { data: u64, } [Program Accounts](https://www.anchor-lang.com/docs/basics/idl#program-accounts) --------------------------------------------------------------------------------- The `accounts` array in the IDL corresponds to the structs in a program annotated with the `#[account]` attribute. These structs define the data stored on accounts created by the program. ProgramIDLClient The program below defines a `NewAccount` struct with a single `data` field of type `u64`. lib.rs use anchor_lang::prelude::*; declare_id!("BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd"); #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.new_account.data = data; msg!("Changed data to: {}!", data); Ok(()) } } #[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>, } #[account] pub struct NewAccount { data: u64, } [Discriminators](https://www.anchor-lang.com/docs/basics/idl#discriminators) ----------------------------------------------------------------------------- Anchor assigns a unique 8 byte discriminator to each instruction and account type in a program. These discriminators serve as identifiers to distinguish between different instructions or account types. The discriminator is generated using the first 8 bytes of the Sha256 hash of a prefix combined with the instruction or account name. As of Anchor v0.30, these discriminators are included in the IDL file. Note that when working with Anchor, you typically won't need to interact directly with these discriminators. This section is primarily to provide context on how the discriminator is generated and used. InstructionsAccounts The instruction discriminator is used by the program to determine which specific instruction to execute when called. When an Anchor program instruction is invoked, the discriminator is included as the first 8 bytes of the instruction data. This is done automatically by the Anchor client. IDL "instructions": [\ {\ "name": "initialize",\ \ \ "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],\ ...\ }\ ] The discriminator for an instruction is the first 8 bytes of the Sha256 hash of the prefix `global` plus the instruction name. For example: sha256("global:initialize") Hexadecimal output: af af 6d 1f 0d 98 9b ed d4 6a 95 07 32 81 ad c2 1b b5 e0 e1 d7 73 b2 fb bd 7a b5 04 cd d4 aa 30 The first 8 bytes are used as the discriminator for the instruction. af = 175 af = 175 6d = 109 1f = 31 0d = 13 98 = 152 9b = 155 ed = 237 You can find the implementation of the discriminator generation in the Anchor codebase [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/program/common.rs#L5-L19) , for the [`gen_discriminator` method here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/program/common.rs#L21-L24) , which is used [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/program/instruction.rs#L33) . [Previous\ \ Program Structure](https://www.anchor-lang.com/docs/basics/program-structure) [Next\ \ Program Derived Address](https://www.anchor-lang.com/docs/basics/pda) ### On this page [Program Instructions](https://www.anchor-lang.com/docs/basics/idl#program-instructions) [Program Accounts](https://www.anchor-lang.com/docs/basics/idl#program-accounts) [Discriminators](https://www.anchor-lang.com/docs/basics/idl#discriminators) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/basics/idl.mdx) --- # Program Derived Address [The Basics](https://www.anchor-lang.com/docs/basics) Program Derived Address ======================= Learn how to use Program Derived Addresses (PDAs) in Anchor programs to create deterministic account addresses. Program Derived Addresses (PDA) refer to a feature of Solana development that allows you to create a unique address derived deterministically from pre-defined inputs (seeds) and a program ID. This section will cover basic examples of how to use PDAs in an Anchor program. [Anchor PDA Constraints](https://www.anchor-lang.com/docs/basics/pda#anchor-pda-constraints) --------------------------------------------------------------------------------------------- When using PDAs in an Anchor program, you generally use Anchor's account constraints to define the seeds to derive the PDA. These constraints serve as security checks to ensure that the correct address is derived. The constraints used to define the PDA seeds include: * `seeds`: An array of optional seeds used to derive the PDA. Seeds can be static values or dynamic references to account data. * `bump`: The bump seed used to derive the PDA. Used to ensure the address falls off the Ed25519 curve and is a valid PDA. * `seeds::program` - (Optional) The program ID used to derive the PDA address. This constraint is only used to derive a PDA where the program ID is not the current program. The `seeds` and `bump` constraints are required to be used together. ### [Usage Examples](https://www.anchor-lang.com/docs/basics/pda#usage-examples) Below are examples demonstrating how to use PDA constraints in an Anchor program. seedsbumpseeds::programinit The `seeds` constraint specifies the optional values used to derive the PDA. #### [No Optional Seeds](https://www.anchor-lang.com/docs/basics/pda#no-optional-seeds) * Use an empty array `[]` to define a PDA without optional seeds. #[derive(Accounts)] pub struct InstructionAccounts<'info> { #[account(\ \ seeds = [],\ bump,\ )] pub pda_account: SystemAccount<'info>, } #### [Single Static Seed](https://www.anchor-lang.com/docs/basics/pda#single-static-seed) * Specify optional seeds in the `seeds` constraint. #[derive(Accounts)] pub struct InstructionAccounts<'info> { #[account(\ \ \ seeds = [b"hello_world"],\ bump,\ )] pub pda_account: SystemAccount<'info>, } #### [Multiple Seeds and Account References](https://www.anchor-lang.com/docs/basics/pda#multiple-seeds-and-account-references) * Multiple seeds can be specified in the `seeds` constraint. The `seeds` constraint can also reference other account addresses or account data. #[derive(Accounts)] pub struct InstructionAccounts<'info> { pub signer: Signer<'info>, #[account(\ \ seeds = [b"hello_world", signer.key().as_ref()],\ bump,\ )] pub pda_account: SystemAccount<'info>, } The example above uses both a static seed (`b"hello_world"`) and a dynamic seed (the signer's public key). [PDA seeds in the IDL](https://www.anchor-lang.com/docs/basics/pda#pda-seeds-in-the-idl) ----------------------------------------------------------------------------------------- Program Derived Address (PDA) seeds defined in the `seeds` constraint are included in the program's IDL file. This allows the Anchor client to automatically resolve account addresses using these seeds when constructing instructions. This example below shows the relationship between the program, IDL, and client. ProgramIDLClient The program below defines a `pda_account` using a static seed (`b"hello_world"`) and the signer's public key as a dynamic seed. use anchor_lang::prelude::*; declare_id!("BZLiJ62bzRryYp9mRobz47uA66WDgtfTXhhgM25tJyx5"); #[program] mod hello_anchor { use super::*; pub fn test_instruction(ctx: Context) -> Result<()> { msg!("PDA: {}", ctx.accounts.pda_account.key()); Ok(()) } } #[derive(Accounts)] pub struct InstructionAccounts<'info> { pub signer: Signer<'info>, #[account(\ \ seeds = [b"hello_world", signer.key().as_ref()],\ bump,\ )] pub pda_account: SystemAccount<'info>, } [Previous\ \ Program IDL File](https://www.anchor-lang.com/docs/basics/idl) [Next\ \ Cross Program Invocation](https://www.anchor-lang.com/docs/basics/cpi) ### On this page [Anchor PDA Constraints](https://www.anchor-lang.com/docs/basics/pda#anchor-pda-constraints) [Usage Examples](https://www.anchor-lang.com/docs/basics/pda#usage-examples) [PDA seeds in the IDL](https://www.anchor-lang.com/docs/basics/pda#pda-seeds-in-the-idl) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/basics/pda.mdx) --- # Cross Program Invocation [The Basics](https://www.anchor-lang.com/docs/basics) Cross Program Invocation ======================== Learn how to implement Cross Program Invocations (CPIs) in Anchor programs to enable composability between different Solana programs. Cross Program Invocations (CPI) refer to the process of one program invoking instructions of another program, which enables the composibility of Solana programs. This section will cover the basics of implementing CPIs in an Anchor program, using a simple SOL transfer instruction as a practical example. Once you understand the basics of how to implement a CPI, you can apply the same concepts for any instruction. [Cross Program Invocations](https://www.anchor-lang.com/docs/basics/cpi#cross-program-invocations) --------------------------------------------------------------------------------------------------- Let's examine a program that implements a CPI to the System Program's transfer instruction. Here is the example program on [Solana Playground](https://beta.solpg.io/66df2751cffcf4b13384d35a) . The `lib.rs` file includes a single `sol_transfer` instruction. When the `sol_transfer` instruction on the Anchor program is invoked, the program internally invokes the transfer instruction of the System Program. lib.rs use anchor_lang::prelude::*; use anchor_lang::system_program::{transfer, Transfer}; declare_id!("9AvUNHjxscdkiKQ8tUn12QCMXtcnbR9BVGq3ULNzFMRi"); #[program] pub mod cpi { use super::*; pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { let from_pubkey = ctx.accounts.sender.to_account_info(); let to_pubkey = ctx.accounts.recipient.to_account_info(); let program_id = ctx.accounts.system_program.to_account_info(); let cpi_context = CpiContext::new( program_id, Transfer { from: from_pubkey, to: to_pubkey, }, ); transfer(cpi_context, amount)?; Ok(()) } } #[derive(Accounts)] pub struct SolTransfer<'info> { #[account(mut)] sender: Signer<'info>, #[account(mut)] recipient: SystemAccount<'info>, system_program: Program<'info, System>, } The `cpi.test.ts` file shows how to invoke the Anchor program's `sol_transfer` instruction and logs a link to the transaction details on SolanaFM. cpi.test.ts it("SOL Transfer Anchor", async () => { const transactionSignature = await program.methods .solTransfer(new BN(transferAmount)) .accounts({ sender: sender.publicKey, recipient: recipient.publicKey, }) .rpc(); console.log( `\nTransaction Signature:` + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, ); }); You can build, deploy, and run the test for this example on Playground to view the transaction details on the [SolanaFM explorer](https://solana.fm/) . The transaction details will show that the Anchor program was first invoked (instruction 1), which then invokes the System Program (instruction 1.1), resulting in a successful SOL transfer. ![Transaction Details](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftransaction-details.1e2d079c.png&w=3840&q=75) ### [Example Explanation](https://www.anchor-lang.com/docs/basics/cpi#example-explanation) Cross Program Invocations (CPIs) allow one program to invoke instructions on another program. The process of implementing a CPI is the same as that of creating a instruction where you must specify: 1. The program ID of the program being called 2. The accounts required by the instruction 3. Any instruction data required as arguments This pattern ensures the CPI has all the information needed to invoke the target program's instruction. The System Program's transfer instruction requires two accounts: * `from`: The account sending SOL. * `to`: The account receiving SOL. In the example program, the `SolTransfer` struct specifies the accounts required by the transfer instruction. The System Program is also included because the CPI invokes the System Program. #[derive(Accounts)] pub struct SolTransfer<'info> { #[account(mut)] sender: Signer<'info>, // from account #[account(mut)] recipient: SystemAccount<'info>, // to account system_program: Program<'info, System>, // program ID } The following tabs present three approaches to implementing Cross Program Invocations (CPIs), each at a different level of abstraction. All examples are functionally equivalent. The main purpose is to illustrate the implementation details of a CPI. 123 The `sol_transfer` instruction included in the example code shows a typical approach for constructing CPIs using the Anchor framework. This approach involves creating a [`CpiContext`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/context.rs#L171) , which includes the `program_id` and accounts required for the instruction being called. The `CpiContext` is then passed to an Anchor helper function ([`transfer`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/system_program.rs#L298) ) to invoke a specific instruction. use anchor_lang::system_program::{transfer, Transfer}; pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { let from_pubkey = ctx.accounts.sender.to_account_info(); let to_pubkey = ctx.accounts.recipient.to_account_info(); let program_id = ctx.accounts.system_program.to_account_info(); let cpi_context = CpiContext::new( program_id, Transfer { from: from_pubkey, to: to_pubkey, }, ); transfer(cpi_context, amount)?; Ok(()) } The `cpi_context` variable specifies the program ID (System Program) and accounts (sender and recipient) required by the transfer instruction. let cpi_context = CpiContext::new( program_id, Transfer { from: from_pubkey, to: to_pubkey, }, ); The `cpi_context` and `amount` are then passed into the `transfer` function to execute the CPI invoking the transfer instruction of the System Program. transfer(cpi_context, amount)?; Here is a reference program on [Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/cpi) which includes all 3 examples. [Cross Program Invocations with PDA Signers](https://www.anchor-lang.com/docs/basics/cpi#cross-program-invocations-with-pda-signers) ------------------------------------------------------------------------------------------------------------------------------------- Next, let's examine a program that implements a CPI to the System Program's transfer instruction where the sender is a Program Derived Address (PDA) that must be "signed" for by the program. Here is the example program on [Solana Playground](https://beta.solpg.io/66df2bd2cffcf4b13384d35b) . The `lib.rs` file includes the following program with a single `sol_transfer` instruction. lib.rs use anchor_lang::prelude::*; use anchor_lang::system_program::{transfer, Transfer}; declare_id!("3455LkCS85a4aYmSeNbRrJsduNQfYRY82A7eCD3yQfyR"); #[program] pub mod cpi { use super::*; pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { let from_pubkey = ctx.accounts.pda_account.to_account_info(); let to_pubkey = ctx.accounts.recipient.to_account_info(); let program_id = ctx.accounts.system_program.to_account_info(); let seed = to_pubkey.key(); let bump_seed = ctx.bumps.pda_account; let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; let cpi_context = CpiContext::new( program_id, Transfer { from: from_pubkey, to: to_pubkey, }, ) .with_signer(signer_seeds); transfer(cpi_context, amount)?; Ok(()) } } #[derive(Accounts)] pub struct SolTransfer<'info> { #[account(\ mut,\ seeds = [b"pda", recipient.key().as_ref()],\ bump,\ )] pda_account: SystemAccount<'info>, #[account(mut)] recipient: SystemAccount<'info>, system_program: Program<'info, System>, } The `cpi.test.ts` file shows how to invoke the Anchor program's `sol_transfer` instruction and logs a link to the transaction details on SolanaFM. It shows how to derive the PDA using the seeds specified in the program: const [PDA] = PublicKey.findProgramAddressSync( [Buffer.from("pda"), wallet.publicKey.toBuffer()], program.programId, ); The first step in this example is to fund the PDA account with a basic SOL transfer from the Playground wallet. cpi.test.ts it("Fund PDA with SOL", async () => { const transferInstruction = SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: PDA, lamports: transferAmount, }); const transaction = new Transaction().add(transferInstruction); const transactionSignature = await sendAndConfirmTransaction( connection, transaction, [wallet.payer], // signer ); console.log( `\nTransaction Signature:` + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, ); }); Once the PDA is funded with SOL, invoke the `sol_transfer` instruction. This instruction transfers SOL from the PDA account back to the `wallet` account via a CPI to the System Program, which is "signed" for by the program. it("SOL Transfer with PDA signer", async () => { const transactionSignature = await program.methods .solTransfer(new BN(transferAmount)) .accounts({ pdaAccount: PDA, recipient: wallet.publicKey, }) .rpc(); console.log( `\nTransaction Signature: https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, ); }); You can build, deploy, and run the test to view the transaction details on the [SolanaFM explorer](https://solana.fm/) . The transaction details will show that the custom program was first invoked (instruction 1), which then invokes the System Program (instruction 1.1), resulting in a successful SOL transfer. ![Transaction Details](https://www.anchor-lang.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftransaction-details-pda.4a9d81a7.png&w=3840&q=75) ### [Example Explanation](https://www.anchor-lang.com/docs/basics/cpi#example-explanation-1) In the example code, the `SolTransfer` struct specifies the accounts required by the transfer instruction. The sender is a PDA that the program must sign for. The `seeds` to derive the address for the `pda_account` include the hardcoded string "pda" and the address of the `recipient` account. This means the address for the `pda_account` is unique for each `recipient`. #[derive(Accounts)] pub struct SolTransfer<'info> { #[account(\ mut,\ \ seeds = [b"pda", recipient.key().as_ref()],\ bump,\ )] pda_account: SystemAccount<'info>, #[account(mut)] recipient: SystemAccount<'info>, system_program: Program<'info, System>, } The Javascript equivalent to derive the PDA is included in the test file. const [PDA] = PublicKey.findProgramAddressSync( [Buffer.from("pda"), wallet.publicKey.toBuffer()], program.programId, ); The following tabs present two approaches to implementing Cross Program Invocations (CPIs), each at a different level of abstraction. Both examples are functionally equivalent. The main purpose is to illustrate the implementation details of the CPI. 12 The `sol_transfer` instruction included in the example code shows a typical approach for constructing CPIs using the Anchor framework. This approach involves creating a [`CpiContext`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/context.rs#L171) , which includes the `program_id` and accounts required for the instruction being called, followed by a helper function (`transfer`) to invoke a specific instruction. pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { let from_pubkey = ctx.accounts.pda_account.to_account_info(); let to_pubkey = ctx.accounts.recipient.to_account_info(); let program_id = ctx.accounts.system_program.to_account_info(); let seed = to_pubkey.key(); let bump_seed = ctx.bumps.pda_account; let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; let cpi_context = CpiContext::new( program_id, Transfer { from: from_pubkey, to: to_pubkey, }, ) .with_signer(signer_seeds); transfer(cpi_context, amount)?; Ok(()) } When signing with PDAs, the seeds and bump seed are included in the `cpi_context` as `signer_seeds` using `with_signer()`. The bump seed for a PDA can be accessed using `ctx.bumps` followed by the name of the PDA account. let seed = to_pubkey.key(); let bump_seed = ctx.bumps.pda_account; let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; let cpi_context = CpiContext::new( program_id, Transfer { from: from_pubkey, to: to_pubkey, }, ) .with_signer(signer_seeds); The `cpi_context` and `amount` are then passed into the `transfer` function to execute the CPI. transfer(cpi_context, amount)?; When the CPI is processed, the Solana runtime will validate that the provided seeds and caller program ID derive a valid PDA. The PDA is then added as a signer on the invocation. This mechanism allows for programs to sign for PDAs that are derived from their program ID. Here is a reference program on [Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/cpi-pda) which includes both examples. [Previous\ \ Program Derived Address](https://www.anchor-lang.com/docs/basics/pda) [Next\ \ Clients](https://www.anchor-lang.com/docs/clients) ### On this page [Cross Program Invocations](https://www.anchor-lang.com/docs/basics/cpi#cross-program-invocations) [Example Explanation](https://www.anchor-lang.com/docs/basics/cpi#example-explanation) [Cross Program Invocations with PDA Signers](https://www.anchor-lang.com/docs/basics/cpi#cross-program-invocations-with-pda-signers) [Example Explanation](https://www.anchor-lang.com/docs/basics/cpi#example-explanation-1) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/basics/cpi.mdx) --- # Clients Clients ======= Learn how to interact with Anchor programs using client libraries in TypeScript and Rust. [### TypeScript\ \ Learn how to use Anchor's TypeScript client library to interact with Solana programs](https://www.anchor-lang.com/docs/clients/typescript) [### Rust\ \ Learn how to use Anchor's Rust client library to interact with Solana programs](https://www.anchor-lang.com/docs/clients/rust) [Previous\ \ Cross Program Invocation](https://www.anchor-lang.com/docs/basics/cpi) [Next\ \ TypeScript](https://www.anchor-lang.com/docs/clients/typescript) ### On this page No Headings [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/clients/index.mdx) --- # TypeScript [Client Libraries](https://www.anchor-lang.com/docs/clients) TypeScript ========== Learn how to use Anchor's TypeScript client library to interact with Solana programs Anchor provides a Typescript client library ([@coral-xyz/anchor](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor) ) that simplifies the process of interacting with Solana programs from the client in JavaScript or TypeScript. The `@coral-xyz/anchor` library is only compatible with the legacy version (v1) of `@solana/web3.js` and `@solana/spl-token`. It is not compatible with the new version (v2) of `@solana/web3.js`. [Client Program](https://www.anchor-lang.com/docs/clients/typescript#client-program) ------------------------------------------------------------------------------------- To interact with an Anchor program using `@coral-xyz/anchor`, you'll need to create a [`Program`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/index.ts#L58) instance using the program's [IDL file](https://www.anchor-lang.com/docs/basics/idl) . Creating an instance of the `Program` requires the program's IDL and an [`AnchorProvider`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/provider.ts#L59) . An `AnchorProvider` is an abstraction that combines two things: * `Connection` - the connection to a Solana cluster (i.e. localhost, devnet, mainnet) * `Wallet` - (optional) a default wallet used to pay for and sign transactions Frontend/NodeTest File When integrating with a frontend using the [Solana wallet adapter](https://github.com/anza-xyz/wallet-adapter) , you'll need to set up the `AnchorProvider` and `Program`. example import { Program, AnchorProvider, setProvider } from "@coral-xyz/anchor"; import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react"; import type { HelloAnchor } from "./idlType"; import idl from "./idl.json"; const { connection } = useConnection(); const wallet = useAnchorWallet(); const provider = new AnchorProvider(connection, wallet, {}); setProvider(provider); export const program = new Program(idl as HelloAnchor, { connection, }); In the code snippet above: * `idl.json` is the IDL file generated by Anchor, found at `/target/idl/.json` in an Anchor project. * `idlType.ts` is the IDL type (for use with TypeScript), found at `/target/types/.ts` in an Anchor project. Alternatively, you can create an `Program` instance using only the IDL and the `Connection` to a Solana cluster. This means there is no default `Wallet`, but allows you to use the `Program` to fetch accounts or build instructions without a connected wallet. import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js"; import { Program } from "@coral-xyz/anchor"; import type { HelloAnchor } from "./idlType"; import idl from "./idl.json"; const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); export const program = new Program(idl as HelloAnchor, { connection, }); [Invoke Instructions](https://www.anchor-lang.com/docs/clients/typescript#invoke-instructions) ----------------------------------------------------------------------------------------------- Once the `Program` is set up using a program's IDL file, you can use the Anchor [`MethodsBuilder`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/namespace/methods.ts#L155) to: * Build individual instructions * Build transactions * Build and send transactions The basic format looks like the following: methodsinstructionaccountssigners `program.methods` - This is the builder API for creating instruction calls from the program's IDL await program.methods .instructionName(instructionData) .accounts({}) .signers([]) .rpc(); Anchor provides multiple methods for building program instructions: .rpc.transaction.instruction The [`rpc()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/namespace/methods.ts#L428) method [sends a signed transaction](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/namespace/rpc.ts#L29) with the specified instruction and returns a `TransactionSignature`. When using `.rpc`, the `Wallet` from the `Provider` is automatically included as a signer. // Generate keypair for the new account const newAccountKp = new Keypair(); const data = new BN(42); const transactionSignature = await program.methods .initialize(data) .accounts({ newAccount: newAccountKp.publicKey, signer: wallet.publicKey, systemProgram: SystemProgram.programId, }) .signers([newAccountKp]) .rpc(); [Fetch Accounts](https://www.anchor-lang.com/docs/clients/typescript#fetch-accounts) ------------------------------------------------------------------------------------- The `Program` client simplifies the process of fetching and deserializing accounts created by your Anchor program. Use `program.account` followed by the name of the account type defined in the IDL. Anchor provides multiple methods for fetching accounts. allmemcmpfetchfetchMultiple Use [`all()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/namespace/account.ts#L251) to fetch all existing accounts for a specific account type. const accounts = await program.account.newAccount.all(); [Example](https://www.anchor-lang.com/docs/clients/typescript#example) ----------------------------------------------------------------------- The example below demonstrates how to use `@coral-xyz/anchor` to interact with a simple Anchor program. The program has two instructions: * `initialize` – Creates and initializes a counter account to store a value * `increment` – Increments the value stored on the counter account lib.rs use anchor_lang::prelude::*; declare_id!("6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC"); #[program] pub mod example { use super::*; pub fn initialize(ctx: Context) -> Result<()> { let counter = &ctx.accounts.counter; msg!("Counter account created! Current count: {}", counter.count); Ok(()) } pub fn increment(ctx: Context) -> Result<()> { let counter = &mut ctx.accounts.counter; msg!("Previous counter: {}", counter.count); 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\ )] pub counter: Account<'info, Counter>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Increment<'info> { #[account(mut)] pub counter: Account<'info, Counter>, } #[account] pub struct Counter { pub count: u64, } Below is an example folder structure for a TypeScript client that interacts with the Anchor program: ts idl example.json example.ts example.ts package.json The `/idl` directory in the example includes two files: * `example.json`: The IDL file for the program * `example.ts`: A TypeScript type definition file generated for the IDL The tabs below include the `example.json` and `example.ts` files as a reference of what these files look like. example.jsonexample.ts { "address": "6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC", "metadata": { "name": "example", "version": "0.1.0", "spec": "0.1.0", "description": "Created with Anchor" }, "instructions": [\ {\ "name": "increment",\ "discriminator": [11, 18, 104, 9, 104, 174, 59, 33],\ "accounts": [\ {\ "name": "counter",\ "writable": true\ }\ ],\ "args": []\ },\ {\ "name": "initialize",\ "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],\ "accounts": [\ {\ "name": "payer",\ "writable": true,\ "signer": true\ },\ {\ "name": "counter",\ "writable": true,\ "signer": true\ },\ {\ "name": "system_program",\ "address": "11111111111111111111111111111111"\ }\ ],\ "args": []\ }\ ], "accounts": [\ {\ "name": "Counter",\ "discriminator": [255, 176, 4, 245, 188, 253, 124, 25]\ }\ ], "types": [\ {\ "name": "Counter",\ "type": {\ "kind": "struct",\ "fields": [\ {\ "name": "count",\ "type": "u64"\ }\ ]\ }\ }\ ] } When you run `anchor build` in an Anchor project, the Anchor CLI automatically generates: * The IDL file (`.json`) in the `target/idl` folder (ex. `target/idl/example.json`) * The TypeScript type definitions (`.ts`) in the `target/types` folder (ex. `target/types/example.ts`) The `example.ts` file below includes the script to interact with the program. example.ts import { Connection, Keypair, LAMPORTS_PER_SOL, Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; import { Program } from "@coral-xyz/anchor"; import type { Example } from "./idl/example.ts"; import idl from "./idl/example.json"; // Set up a connection to the cluster const connection = new Connection("http://127.0.0.1:8899", "confirmed"); // Create a Program instance using the IDL and connection const program = new Program(idl as Example, { connection, }); // Generate new Keypairs for the payer and the counter account const payer = Keypair.generate(); const counter = Keypair.generate(); // Airdrop SOL to fund the payer's account for transaction fees const airdropTransactionSignature = await connection.requestAirdrop( payer.publicKey, LAMPORTS_PER_SOL, ); await connection.confirmTransaction(airdropTransactionSignature); // Build the initialize instruction const initializeInstruction = await program.methods .initialize() .accounts({ payer: payer.publicKey, counter: counter.publicKey, }) .instruction(); // Build the increment instruction const incrementInstruction = await program.methods .increment() .accounts({ counter: counter.publicKey, }) .instruction(); // Add both instructions to a single transaction const transaction = new Transaction().add( initializeInstruction, incrementInstruction, ); // Send the transaction const transactionSignature = await sendAndConfirmTransaction( connection, transaction, [payer, counter], ); console.log("Transaction Signature", transactionSignature); // Fetch the counter account const counterAccount = await program.account.counter.fetch(counter.publicKey); console.log("Count:", counterAccount.count); [Previous\ \ Clients](https://www.anchor-lang.com/docs/clients) [Next\ \ Rust](https://www.anchor-lang.com/docs/clients/rust) ### On this page [Client Program](https://www.anchor-lang.com/docs/clients/typescript#client-program) [Invoke Instructions](https://www.anchor-lang.com/docs/clients/typescript#invoke-instructions) [Fetch Accounts](https://www.anchor-lang.com/docs/clients/typescript#fetch-accounts) [Example](https://www.anchor-lang.com/docs/clients/typescript#example) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/clients/typescript.mdx) --- # Dependency Free Composability [Additional Features](https://www.anchor-lang.com/docs/features) Dependency Free Composability ============================= Learn how to use Anchor's declare\_program macro to interact with programs without additional dependencies. The [`declare_program!()`](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program) macro simplifies the process of interacting with Anchor programs by generating Rust modules (from a program's IDL) that can be used in both on-chain and off-chain code. You can find an example program [here](https://github.com/coral-xyz/anchor/tree/master/tests/declare-program) . The following modules are generated by the `declare_program!()` macro: | Module | Description | | --- | --- | | [`cpi`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/cpi.rs) | Helper functions for making cross-program invocations (CPIs) to the program from other on-chain programs | | [`client`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/client.rs) | Accounts and arguments required to build program instructions to add to client-side transactions | | [`account`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/accounts.rs) | Account data types (program state) defined in the program | | [`program`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/program.rs) | Program ID constant used to identify the program | | [`constants`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/constants.rs) | Program constants defined in the program | | [`events`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/events.rs) | Program events defined in the program | | [`types`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/types.rs) | Program types defined in the program | | [`errors`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/errors.rs) | Program errors defined in the program | [Examples](https://www.anchor-lang.com/docs/features/declare-program#examples) ------------------------------------------------------------------------------- The following examples demonstrate how to use the `declare_program!()` macro in two scenarios: 1. Making Cross Program Invocations (CPIs) from one program to another program 2. Building client-side transactions to invoke a program's instructions Both examples show how the modules generated by the `declare_program!()` macro simplify program interactions, whether you're writing on-chain or off-chain code. ### [On-chain CPI](https://www.anchor-lang.com/docs/features/declare-program#on-chain-cpi) To use the `declare_program!()` macro, you need the IDL file for the target program. The IDL file must be placed in a directory named `/idls` in your project. The `/idls` directory can be located at any level in your project structure. For example, your project could have this layout: idls example.json programs example-cpi src lib.rs Cargo.toml Below is the source code (`lib.rs`) for the target (callee) program that generates the `example.json` IDL file shown above. Using the program's IDL file, another program can use the `declare_program!()` macro to generate a CPI module, enabling it to make CPIs to this program's instructions. Callee ProgramIDL use anchor_lang::prelude::*; declare_id!("8HupNBr7SBhBLcBsLhbtes3tCarBm6Bvpqp5AfVjHuj8"); #[program] pub mod example { use super::*; pub fn initialize(ctx: Context) -> Result<()> { let counter = &ctx.accounts.counter; msg!("Counter account created! Current count: {}", counter.count); Ok(()) } pub fn increment(ctx: Context) -> Result<()> { let counter = &mut ctx.accounts.counter; msg!("Previous counter: {}", counter.count); 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\ )] pub counter: Account<'info, Counter>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Increment<'info> { #[account(mut)] pub counter: Account<'info, Counter>, } #[account] pub struct Counter { pub count: u64, } Below is the source code (`lib.rs`) for the caller program (example-cpi) that uses the `declare_program!()` macro to generate a CPI module to invoke the instructions defined in the callee program above. Caller ProgramTest use anchor_lang::prelude::*; declare_id!("GENmb1D59wqCKRwujq4PJ8461EccQ5srLHrXyXp4HMTH"); declare_program!(example); use example::{ accounts::Counter, cpi::{ self, accounts::{Increment, Initialize}, }, program::Example, }; #[program] pub mod example_cpi { use super::*; pub fn initialize_cpi(ctx: Context) -> Result<()> { // Create CPI context for initialize let cpi_ctx = CpiContext::new( ctx.accounts.example_program.to_account_info(), Initialize { payer: ctx.accounts.payer.to_account_info(), counter: ctx.accounts.counter.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), }, ); // Invoke the initialize instruction cpi::initialize(cpi_ctx)?; Ok(()) } pub fn increment_cpi(ctx: Context) -> Result<()> { // Create CPI context for increment let cpi_ctx = CpiContext::new( ctx.accounts.example_program.to_account_info(), Increment { counter: ctx.accounts.counter.to_account_info(), }, ); // Invoke the increment instruction cpi::increment(cpi_ctx)?; Ok(()) } } #[derive(Accounts)] pub struct InitializeCpi<'info> { #[account(mut)] pub payer: Signer<'info>, #[account(mut)] pub counter: Signer<'info>, pub system_program: Program<'info, System>, pub example_program: Program<'info, Example>, } #[derive(Accounts)] pub struct IncrementCpi<'info> { #[account(mut)] pub counter: Account<'info, Counter>, pub example_program: Program<'info, Example>, } #### [Explanation](https://www.anchor-lang.com/docs/features/declare-program#explanation) The `declare_program!()` macro takes a single argument - the name of the program's IDL file (e.g. `example.json`): declare_program!(example); // Looks for /idls/example.json Bring into scope the generated modules: use example::{ accounts::Counter, // Account types cpi::{ // Cross program invocation helpers self, accounts::{Increment, Initialize}, }, program::Example, // Program type }; Use the imported types in the account validation structs: #[derive(Accounts)] pub struct IncrementCpi<'info> { // Counter type from accounts module #[account(mut)] pub counter: Account<'info, Counter>, // Example type from program module pub example_program: Program<'info, Example>, } Use the CPI module to invoke the program's instructions: pub fn initialize_cpi(ctx: Context) -> Result<()> { // Create CPI context for initialize let cpi_ctx = CpiContext::new( ctx.accounts.example_program.to_account_info(), Initialize { payer: ctx.accounts.payer.to_account_info(), counter: ctx.accounts.counter.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), }, ); // Invoke the initialize instruction cpi::initialize(cpi_ctx)?; Ok(()) } pub fn increment_cpi(ctx: Context) -> Result<()> { // Create CPI context for increment let cpi_ctx = CpiContext::new( ctx.accounts.example_program.to_account_info(), Increment { counter: ctx.accounts.counter.to_account_info(), }, ); // Invoke the increment instruction cpi::increment(cpi_ctx)?; Ok(()) } ### [Off-chain Client](https://www.anchor-lang.com/docs/features/declare-program#off-chain-client) To use the `declare_program!()` macro, you need the IDL file for the target program. The IDL file must be placed in a directory named `/idls` in your project. The `/idls` directory can be located at any level in your project structure. For example, your project could have this layout: idls example.json src main.rs Cargo.toml Below is the source code (`lib.rs`) for the target program that generates the `example.json` IDL file shown above. The program's IDL can then be used in a client script along with the `declare_program!()` macro to generate a Client module to build the program's instructions. Callee ProgramIDL use anchor_lang::prelude::*; declare_id!("6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC"); #[program] pub mod example { use super::*; pub fn initialize(ctx: Context) -> Result<()> { let counter = &ctx.accounts.counter; msg!("Counter account created! Current count: {}", counter.count); Ok(()) } pub fn increment(ctx: Context) -> Result<()> { let counter = &mut ctx.accounts.counter; msg!("Previous counter: {}", counter.count); 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\ )] pub counter: Account<'info, Counter>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Increment<'info> { #[account(mut)] pub counter: Account<'info, Counter>, } #[account] pub struct Counter { pub count: u64, } Below is the client script (main.rs) that uses the `declare_program!()` macro to generate a Client module to build the program's instructions. Client ScriptDependencies use anchor_client::{ solana_client::rpc_client::RpcClient, solana_sdk::{ commitment_config::CommitmentConfig, native_token::LAMPORTS_PER_SOL, signature::Keypair, signer::Signer, system_program, }, Client, Cluster, }; use anchor_lang::prelude::*; use std::rc::Rc; declare_program!(example); use example::{accounts::Counter, client::accounts, client::args}; #[tokio::main] async fn main() -> anyhow::Result<()> { let connection = RpcClient::new_with_commitment( "http://127.0.0.1:8899", // Local validator URL CommitmentConfig::confirmed(), ); // Generate Keypairs and request airdrop let payer = Keypair::new(); let counter = Keypair::new(); println!("Generated Keypairs:"); println!(" Payer: {}", payer.pubkey()); println!(" Counter: {}", counter.pubkey()); println!("\nRequesting 1 SOL airdrop to payer"); let airdrop_signature = connection.request_airdrop(&payer.pubkey(), LAMPORTS_PER_SOL)?; // Wait for airdrop confirmation while !connection.confirm_transaction(&airdrop_signature)? { std::thread::sleep(std::time::Duration::from_millis(100)); } println!(" Airdrop confirmed!"); // Create program client let provider = Client::new_with_options( Cluster::Localnet, Rc::new(payer), CommitmentConfig::confirmed(), ); let program = provider.program(example::ID)?; // Build and send instructions println!("\nSend transaction with initialize and increment instructions"); let initialize_ix = program .request() .accounts(accounts::Initialize { counter: counter.pubkey(), payer: program.payer(), system_program: system_program::ID, }) .args(args::Initialize) .instructions()? .remove(0); let increment_ix = program .request() .accounts(accounts::Increment { counter: counter.pubkey(), }) .args(args::Increment) .instructions()? .remove(0); let signature = program .request() .instruction(initialize_ix) .instruction(increment_ix) .signer(&counter) .send() .await?; println!(" Transaction confirmed: {}", signature); println!("\nFetch counter account data"); let counter_account: Counter = program.account::(counter.pubkey()).await?; println!(" Counter value: {}", counter_account.count); Ok(()) } The `declare_program!()` macro takes a single argument - the name of the program's IDL file (e.g. `example.json`): declare_program!(example); // Looks for /idls/example.json Bring into scope the generated modules: use example::{ accounts::Counter, // Program Account types client::accounts, // Accounts for program instructions client::args, // Arguments for program instructions }; Use the Client module to build the program's instructions: // Build initialize instruction let initialize_ix = program .request() // Accounts required for initialize instruction .accounts(accounts::Initialize { counter: counter.pubkey(), payer: program.payer(), system_program: system_program::ID, }) // Arguments for initialize instruction (discriminator) .args(args::Initialize) .instructions()? .remove(0); // Build increment instruction let increment_ix = program .request() // Accounts required for increment instruction .accounts(accounts::Increment { counter: counter.pubkey(), }) // Arguments for increment instruction (discriminator) .args(args::Increment) .instructions()? .remove(0); Add the program's instructions to a transaction and send the transaction: let signature = program .request() .instruction(initialize_ix) .instruction(increment_ix) .signer(&counter) .send() .await?; Use the Account module to fetch and deserialize the program's account types: // Counter type from accounts module let counter_account: Counter = program.account::(counter.pubkey()).await?; [Previous\ \ Features](https://www.anchor-lang.com/docs/features) [Next\ \ Custom Errors](https://www.anchor-lang.com/docs/features/errors) ### On this page [Examples](https://www.anchor-lang.com/docs/features/declare-program#examples) [On-chain CPI](https://www.anchor-lang.com/docs/features/declare-program#on-chain-cpi) [Off-chain Client](https://www.anchor-lang.com/docs/features/declare-program#off-chain-client) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/features/declare-program.mdx) --- # Rust [Client Libraries](https://www.anchor-lang.com/docs/clients) Rust ==== Learn how to use Anchor's Rust client library to interact with Solana programs The [`anchor-client`](https://docs.rs/anchor-client/latest/anchor_client/) crate is the Rust client library for interacting with Anchor programs. You can find the source code [here](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/client) . [Example](https://www.anchor-lang.com/docs/clients/rust#example) ----------------------------------------------------------------- The example below demonstrates how to use the `anchor-client` crate to interact with a simple Anchor program. The program client can be automatically generated from the program's IDL using the `declare_program!` macro. This macro generates dependency free modules that enable you to interact with the program's instructions and accounts. The program has two instructions: * `initialize` – Creates and initializes a counter account to store a value * `increment` – Increments the value stored on the counter account lib.rs use anchor_lang::prelude::*; declare_id!("6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC"); #[program] pub mod example { use super::*; pub fn initialize(ctx: Context) -> Result<()> { let counter = &ctx.accounts.counter; msg!("Counter account created! Current count: {}", counter.count); Ok(()) } pub fn increment(ctx: Context) -> Result<()> { let counter = &mut ctx.accounts.counter; msg!("Previous counter: {}", counter.count); 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\ )] pub counter: Account<'info, Counter>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Increment<'info> { #[account(mut)] pub counter: Account<'info, Counter>, } #[account] pub struct Counter { pub count: u64, } Below is an example folder structure for a Rust client that interacts with the Anchor program: client-example idls example.json src main.rs target Cargo.toml The program IDL must be in a `/idls` folder. The `declare_program!` macro searches for the IDL in the `/idls` folder to generate the client modules. idls/example.json { "address": "6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC", "metadata": { "name": "example", "version": "0.1.0", "spec": "0.1.0", "description": "Created with Anchor" }, "instructions": [\ {\ "name": "increment",\ "discriminator": [11, 18, 104, 9, 104, 174, 59, 33],\ "accounts": [\ {\ "name": "counter",\ "writable": true\ }\ ],\ "args": []\ },\ {\ "name": "initialize",\ "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],\ "accounts": [\ {\ "name": "payer",\ "writable": true,\ "signer": true\ },\ {\ "name": "counter",\ "writable": true,\ "signer": true\ },\ {\ "name": "system_program",\ "address": "11111111111111111111111111111111"\ }\ ],\ "args": []\ }\ ], "accounts": [\ {\ "name": "Counter",\ "discriminator": [255, 176, 4, 245, 188, 253, 124, 25]\ }\ ], "types": [\ {\ "name": "Counter",\ "type": {\ "kind": "struct",\ "fields": [\ {\ "name": "count",\ "type": "u64"\ }\ ]\ }\ }\ ] } Below is the `src/main.rs` file for interacting with the program: 1. The `declare_program!` macro - Generates client modules for the program using the IDL file 2. The `anchor_client` crate - Provides utilities for interacting with the program, including: * Building program instructions * Sending transactions * Fetching program accounts src/main.rs use anchor_client::{ solana_client::rpc_client::RpcClient, solana_sdk::{ commitment_config::CommitmentConfig, native_token::LAMPORTS_PER_SOL, signature::Keypair, signer::Signer, system_program, }, Client, Cluster, }; use anchor_lang::prelude::*; use std::rc::Rc; declare_program!(example); use example::{accounts::Counter, client::accounts, client::args}; #[tokio::main] async fn main() -> anyhow::Result<()> { let connection = RpcClient::new_with_commitment( "http://127.0.0.1:8899", // Local validator URL CommitmentConfig::confirmed(), ); // Generate Keypairs and request airdrop let payer = Keypair::new(); let counter = Keypair::new(); println!("Generated Keypairs:"); println!(" Payer: {}", payer.pubkey()); println!(" Counter: {}", counter.pubkey()); println!("\nRequesting 1 SOL airdrop to payer"); let airdrop_signature = connection.request_airdrop(&payer.pubkey(), LAMPORTS_PER_SOL)?; // Wait for airdrop confirmation while !connection.confirm_transaction(&airdrop_signature)? { std::thread::sleep(std::time::Duration::from_millis(100)); } println!(" Airdrop confirmed!"); // Create program client let provider = Client::new_with_options( Cluster::Localnet, Rc::new(payer), CommitmentConfig::confirmed(), ); let program = provider.program(example::ID)?; // Build and send instructions println!("\nSend transaction with initialize and increment instructions"); let initialize_ix = program .request() .accounts(accounts::Initialize { counter: counter.pubkey(), payer: program.payer(), system_program: system_program::ID, }) .args(args::Initialize) .instructions()? .remove(0); let increment_ix = program .request() .accounts(accounts::Increment { counter: counter.pubkey(), }) .args(args::Increment) .instructions()? .remove(0); let signature = program .request() .instruction(initialize_ix) .instruction(increment_ix) .signer(&counter) .send() .await?; println!(" Transaction confirmed: {}", signature); println!("\nFetch counter account data"); let counter_account: Counter = program.account::(counter.pubkey()).await?; println!(" Counter value: {}", counter_account.count); Ok(()) } Below are the dependencies for the `Cargo.toml` file: Cargo.toml [package] name = "rs" version = "0.1.0" edition = "2021" [dependencies] anchor-client = { version = "0.31.1", features = ["async"] } anchor-lang = "0.31.1" anyhow = "1.0.93" tokio = { version = "1.0", features = ["full"] } [Previous\ \ TypeScript](https://www.anchor-lang.com/docs/clients/typescript) [Next\ \ Testing](https://www.anchor-lang.com/docs/testing) ### On this page [Example](https://www.anchor-lang.com/docs/clients/rust#example) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/clients/rust.mdx) --- # Zero Copy [Additional Features](https://www.anchor-lang.com/docs/features) Zero Copy ========= Learn how to use Anchor's zero-copy deserialization feature to handle large account data in Solana programs. [Usage](https://www.anchor-lang.com/docs/features/zero-copy#usage) ------------------------------------------------------------------- Zero copy is a deserialization feature that allows programs to read account data directly from memory without copying it. This is particularly useful when working with large accounts. To use zero-copy add the `bytemuck` crate to your dependencies. Add the `min_const_generics` feature to allow working with arrays of any size in your zero-copy types. Cargo.toml [dependencies] bytemuck = { version = "1.20.0", features = ["min_const_generics"] } anchor-lang = "0.31.1" ### [Define a Zero Copy Account](https://www.anchor-lang.com/docs/features/zero-copy#define-a-zero-copy-account) To define an account type that uses zero-copy, annotate the struct with [`#[account(zero_copy)]`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/account/src/lib.rs#L417) . #[account(zero_copy)] pub struct Data { // 10240 bytes - 8 bytes account discriminator pub data: [u8; 10232], } The `#[account(zero_copy)]` attribute automatically implements several traits required for zero-copy deserialization: #[derive(Copy, Clone)] #[derive(bytemuck::Zeroable)] #[derive(bytemuck::Pod)] #[repr(C)] struct Data { // --snip-- } ### [Use AccountLoader for Zero Copy Accounts](https://www.anchor-lang.com/docs/features/zero-copy#use-accountloader-for-zero-copy-accounts) To deserialize a zero-copy account, use [`AccountLoader<'info, T>`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/accounts/account_loader.rs#L95-L99) , where `T` is the zero-copy account type defined with the `#[account(zero_copy)]` attribute. For example: #[derive(Accounts)] pub struct InstructionAccounts<'info> { pub zero_copy_account: AccountLoader<'info, Data>, } #### [Initialize a Zero Copy Account](https://www.anchor-lang.com/docs/features/zero-copy#initialize-a-zero-copy-account) The `init` constraint can be used with the `AccountLoader` type to create a zero-copy account. #[derive(Accounts)] pub struct Initialize<'info> { #[account(\ \ \ init,\ // 10240 bytes is max space to allocate with init constraint\ space = 8 + 10232,\ payer = payer,\ )] pub data_account: AccountLoader<'info, Data>, #[account(mut)] pub payer: Signer<'info>, pub system_program: Program<'info, System>, } The `init` constraint is limited to allocating a maximum of 10240 bytes due to CPI limitations. Under the hood, the `init` constraint makes a CPI call to the SystemProgram to create the account. When initializing a zero-copy account for the first time, use [`load_init`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/accounts/account_loader.rs#L199-L221) to get a mutable reference to the account data. The `load_init` method also sets the account discriminator. pub fn initialize(ctx: Context) -> Result<()> { let account = &mut ctx.accounts.data_account.load_init()?; account.data = [1; 10232]; Ok(()) } For accounts that require more than 10240 bytes, use the [`zero`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/codegen/accounts/constraints.rs#L200-L264) constraint instead of `init`. The `zero` constraint verifies the account has not been initialized by checking that its discriminator has not been set. #[derive(Accounts)] pub struct Initialize<'info> { #[account(zero)] pub data_account: AccountLoader<'info, Data>, } With the `zero` constraint, you'll need to first create the account in a separate instruction by directly calling the System Program. This allows you to create accounts up to Solana's maximum account size of 10MB (10\_485\_760 bytes), bypassing the CPI limitation. Just as before, use `load_init` to get a mutable reference to the account data and set the account discriminator. Since 8 bytes are reserved for the account discriminator, the maximum data size is 10\_485\_752 bytes (10MB - 8 bytes). pub fn initialize(ctx: Context) -> Result<()> { let account = &mut ctx.accounts.data_account.load_init()?; account.data = [1; 10_485_752]; Ok(()) } #### [Update a Zero Copy Account](https://www.anchor-lang.com/docs/features/zero-copy#update-a-zero-copy-account) Use [`load_mut`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/accounts/account_loader.rs#L172-L195) when you need mutable access to update an existing zero-copy account: #[derive(Accounts)] pub struct Update<'info> { #[account(mut)] pub data_account: AccountLoader<'info, Data>, } pub fn update(ctx: Context) -> Result<()> { let account = &mut ctx.accounts.data_account.load_mut()?; account.data = [2; 10232]; Ok(()) } #### [Read a Zero Copy Account](https://www.anchor-lang.com/docs/features/zero-copy#read-a-zero-copy-account) Use [`load`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/accounts/account_loader.rs#L154-L169) to only read the account data. #[derive(Accounts)] pub struct ReadOnly<'info> { pub data_account: AccountLoader<'info, Data>, } pub fn read_only(ctx: Context) -> Result<()> { let account = &ctx.accounts.data_account.load()?; msg!("First 10 bytes: {:?}", &account.data[..10]); Ok(()) } [Examples](https://www.anchor-lang.com/docs/features/zero-copy#examples) ------------------------------------------------------------------------- The examples below demonstrate two approaches for initializing zero-copy accounts in Anchor: 1. Using the `init` constraint to initialize the account in a single instruction 2. Using the `zero` constraint to initialize an account with data greater than 10240 bytes ### [Zero Copy](https://www.anchor-lang.com/docs/features/zero-copy#zero-copy) ProgramClient lib.rs use anchor_lang::prelude::*; declare_id!("8B7XpDXjPWodpDUWDSzv4q9k73jB5WdNQXZxNBj1hqw1"); #[program] pub mod zero_copy { use super::*; pub fn initialize(ctx: Context) -> Result<()> { let account = &mut ctx.accounts.data_account.load_init()?; account.data = [1; 10232]; Ok(()) } pub fn update(ctx: Context) -> Result<()> { let account = &mut ctx.accounts.data_account.load_mut()?; account.data = [2; 10232]; Ok(()) } } #[derive(Accounts)] pub struct Initialize<'info> { #[account(\ init,\ // 10240 bytes is max space to allocate with init constraint\ space = 8 + 10232,\ payer = payer,\ )] pub data_account: AccountLoader<'info, Data>, #[account(mut)] pub payer: Signer<'info>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Update<'info> { #[account(mut)] pub data_account: AccountLoader<'info, Data>, } #[account(zero_copy)] pub struct Data { // 10240 bytes - 8 bytes account discriminator pub data: [u8; 10232], } ### [Initialize Large Account](https://www.anchor-lang.com/docs/features/zero-copy#initialize-large-account) When initializing an account that requires more than 10,240 bytes of space, you must split the initialization into two steps: 1. Create the account in a separate instruction invoking the System Program 2. Initialize the account data in your program instruction Note that the maximum Solana account size is 10MB (10\_485\_760 bytes), 8 bytes are reserved for the account discriminator. ProgramClient lib.rs use anchor_lang::prelude::*; declare_id!("CZgWhy3FYPFgKE5v9atSGaiQzbSB7cM38ofwX1XxeCFH"); #[program] pub mod zero_copy_two { use super::*; pub fn initialize(ctx: Context) -> Result<()> { let account = &mut ctx.accounts.data_account.load_init()?; account.data = [1; 10_485_752]; Ok(()) } } #[derive(Accounts)] pub struct Initialize<'info> { #[account(zero)] pub data_account: AccountLoader<'info, Data>, } #[account(zero_copy)] pub struct Data { // 10240 bytes - 8 bytes account discriminator pub data: [u8; 10_485_752], } [Previous\ \ Emit Events](https://www.anchor-lang.com/docs/features/events) [Next\ \ Token Integration with Anchor](https://www.anchor-lang.com/docs/tokens) ### On this page [Usage](https://www.anchor-lang.com/docs/features/zero-copy#usage) [Define a Zero Copy Account](https://www.anchor-lang.com/docs/features/zero-copy#define-a-zero-copy-account) [Use AccountLoader for Zero Copy Accounts](https://www.anchor-lang.com/docs/features/zero-copy#use-accountloader-for-zero-copy-accounts) [Examples](https://www.anchor-lang.com/docs/features/zero-copy#examples) [Zero Copy](https://www.anchor-lang.com/docs/features/zero-copy#zero-copy) [Initialize Large Account](https://www.anchor-lang.com/docs/features/zero-copy#initialize-large-account) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/features/zero-copy.mdx) --- # Testing Testing ======= Learn how to test Anchor programs using various test frameworks in TypeScript and Rust. [### LiteSVM\ \ Write tests for Solana programs in Rust, TS/JS or Python using LiteSVM.](https://www.anchor-lang.com/docs/testing/litesvm) [### Mollusk\ \ Write tests for Solana programs in Rust using Mollusk.](https://www.anchor-lang.com/docs/testing/mollusk) [Previous\ \ Rust](https://www.anchor-lang.com/docs/clients/rust) [Next\ \ LiteSVM](https://www.anchor-lang.com/docs/testing/litesvm) ### On this page No Headings [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/testing/index.mdx) --- # Features Features ======== Learn how to use additional features of the Anchor framework [### Dependency Free Composability\ \ Learn how to use Anchor's declare\_program macro to interact with programs without additional dependencies.](https://www.anchor-lang.com/docs/features/declare-program) [### Custom Errors\ \ Learn how to implement custom error handling in Anchor programs.](https://www.anchor-lang.com/docs/features/errors) [### Emit Events\ \ Learn how to emit events in Anchor programs using emit! and emit\_cpi! macros.](https://www.anchor-lang.com/docs/features/events) [### Zero Copy\ \ Learn how to use Anchor's zero-copy deserialization feature to handle large account data in Solana programs.](https://www.anchor-lang.com/docs/features/zero-copy) [Previous\ \ Mollusk](https://www.anchor-lang.com/docs/testing/mollusk) [Next\ \ Dependency Free Composability](https://www.anchor-lang.com/docs/features/declare-program) ### On this page No Headings [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/features/index.mdx) --- # Token Integration with Anchor Token Integration with Anchor ============================= Learn how to interact with Solana's Token Programs from an Anchor Program. [What are Token Programs?](https://www.anchor-lang.com/docs/tokens#what-are-token-programs) -------------------------------------------------------------------------------------------- On Solana, there are two main token programs (developed by [Anza](https://www.anza.xyz/) , previously Solana Labs): 1. [Token Program (Original)](https://github.com/solana-program/token) * Basic token functionality (mint, transfer, etc.) * Immutable and widely used 2. [Token Extension Program (Token 2022)](https://github.com/solana-program/token-2022) * Includes all original Token Program features * Adds additional functionality through "extensions" * Recommended for new tokens [Invoking Token Programs in an Anchor Program](https://www.anchor-lang.com/docs/tokens#invoking-token-programs-in-an-anchor-program) ------------------------------------------------------------------------------------------------------------------------------------- The [`anchor-spl`](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/spl) crate simplifies the process of interacting with Solana's Token Programs in an Anchor program. This crate includes instructions and account types for both the original Token Program and the newer Token Extension Program (Token 2022). Simply add the `anchor-spl` crate as a dependency to your program and add `"anchor-spl/idl-build"` to idl-build feature list in `Cargo.toml`. For a walkthrough of how to create an Anchor program locally, see the [quickstart page](https://www.anchor-lang.com/docs/quickstart/local) . Terminal cargo add anchor-spl Cargo.toml [features] idl-build = [\ "anchor-lang/idl-build",\ "anchor-spl/idl-build",\ ] [dependencies] anchor-lang = "0.31.1" anchor-spl = "0.31.1" ### [Core Modules](https://www.anchor-lang.com/docs/tokens#core-modules) The most commonly used modules provided by the `anchor-spl` crate include: | Module | Description | | --- | --- | | [`token`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/spl/src/token.rs) | Token Program (legacy) instructions and account types | | [`token_2022`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/spl/src/token_2022.rs) | Token 2022 base instructions (instructions matching the Token Program functionality) | | [`token_2022_extensions`](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/spl/src/token_2022_extensions) | Token 2022 extensions instructions | | [`token_interface`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/spl/src/token_interface.rs) | Implementation of account types that work with both Token Program and Token 2022 Program | | [`associated_token`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/spl/src/associated_token.rs) | Associated token account instruction | The following pages provide examples of how to use the `anchor-spl` crate in an Anchor program. [Previous\ \ Zero Copy](https://www.anchor-lang.com/docs/features/zero-copy) [Next\ \ SPL Token Basics](https://www.anchor-lang.com/docs/tokens/basics) ### On this page [What are Token Programs?](https://www.anchor-lang.com/docs/tokens#what-are-token-programs) [Invoking Token Programs in an Anchor Program](https://www.anchor-lang.com/docs/tokens#invoking-token-programs-in-an-anchor-program) [Core Modules](https://www.anchor-lang.com/docs/tokens#core-modules) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/tokens/index.mdx) --- # Extensions [Interacting with Tokens](https://www.anchor-lang.com/docs/tokens) Extensions ========== Learn how to enable token extensions to add optional features to token mints and accounts using the Token Extensions Program (Token 2022) in an Anchor program. [What are Token Extensions?](https://www.anchor-lang.com/docs/tokens/extensions#what-are-token-extensions) ----------------------------------------------------------------------------------------------------------- The Token Extensions Program (Token 2022) provides additional features through additional instructions referred to as extensions. Extensions are optional functionality that can be added to a token mint or token account. You can find the implementation of these extension instructions in the Token Extensions Program [source code](https://github.com/solana-program/token-2022/tree/main/program/src/extension) . Each extension adds specific state that must be initialized during mint or token account creation. When initializing either type of account, you can enable multiple extensions simultaneously to add different functionality. However, extensions cannot be added after an account is created - you must include all desired extensions during the initial account creation. This is an important consideration when designing your token, as you'll need to plan ahead for which features you want your token to support. Some extensions are incompatible with each other and cannot be enabled simultaneously on the same token mint or token account. For example, you cannot combine the NonTransferable extension with the TransferFeeConfig extension, since they have conflicting behaviors. The Token Extensions Program defines an [`ExtensionType`](https://github.com/solana-program/token-2022/blob/main/program/src/extension/mod.rs#L1054-L1139) enum that specifies all available extensions that can be added to a token mint or token account. Each variant represents a different extension with unique functionality. The `ExtensionType` enum is defined as follows: Token Extensions /// Extensions that can be applied to mints or accounts. Mint extensions must /// only be applied to mint accounts, and account extensions must only be /// applied to token holding accounts. #[repr(u16)] #[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))] #[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] pub enum ExtensionType { /// Used as padding if the account size would otherwise be 355, same as a /// multisig Uninitialized, /// Includes transfer fee rate info and accompanying authorities to withdraw /// and set the fee TransferFeeConfig, /// Includes withheld transfer fees TransferFeeAmount, /// Includes an optional mint close authority MintCloseAuthority, /// Auditor configuration for confidential transfers ConfidentialTransferMint, /// State for confidential transfers ConfidentialTransferAccount, /// Specifies the default Account::state for new Accounts DefaultAccountState, /// Indicates that the Account owner authority cannot be changed ImmutableOwner, /// Require inbound transfers to have memo MemoTransfer, /// Indicates that the tokens from this mint can't be transferred NonTransferable, /// Tokens accrue interest over time, InterestBearingConfig, /// Locks privileged token operations from happening via CPI CpiGuard, /// Includes an optional permanent delegate PermanentDelegate, /// Indicates that the tokens in this account belong to a non-transferable /// mint NonTransferableAccount, /// Mint requires a CPI to a program implementing the "transfer hook" /// interface TransferHook, /// Indicates that the tokens in this account belong to a mint with a /// transfer hook TransferHookAccount, /// Includes encrypted withheld fees and the encryption public that they are /// encrypted under ConfidentialTransferFeeConfig, /// Includes confidential withheld transfer fees ConfidentialTransferFeeAmount, /// Mint contains a pointer to another account (or the same account) that /// holds metadata MetadataPointer, /// Mint contains token-metadata TokenMetadata, /// Mint contains a pointer to another account (or the same account) that /// holds group configurations GroupPointer, /// Mint contains token group configurations TokenGroup, /// Mint contains a pointer to another account (or the same account) that /// holds group member configurations GroupMemberPointer, /// Mint contains token group member configurations TokenGroupMember, /// Mint allowing the minting and burning of confidential tokens ConfidentialMintBurn, /// Tokens whose UI amount is scaled by a given amount ScaledUiAmount, /// Tokens where minting / burning / transferring can be paused Pausable, /// Indicates that the account belongs to a pausable mint PausableAccount, /// Test variable-length mint extension #[cfg(test)] VariableLenMintTest = u16::MAX - 2, /// Padding extension used to make an account exactly Multisig::LEN, used /// for testing #[cfg(test)] AccountPaddingTest, /// Padding extension used to make a mint exactly Multisig::LEN, used for /// testing #[cfg(test)] MintPaddingTest, } Each extension adds specialized functionality by including additional state that must be initialized when creating a mint or token account. All extension specific state is stored in the in the [`tlv_data`](https://github.com/solana-program/token-2022/blob/main/program/src/extension/mod.rs#L541-L549) field, which follows the base account data type. The `tlv_data` (containing extension state) must be further deserialized according to the specific extension types enabled for that account. Token Extensions /// Encapsulates immutable base state data (mint or account) with possible /// extensions, where the base state is Pod for zero-copy serde. #[derive(Debug, PartialEq)] pub struct PodStateWithExtensions<'data, S: BaseState + Pod> { /// Unpacked base data pub base: &'data S, /// Slice of data containing all TLV data, deserialized on demand tlv_data: &'data [u8], } [Examples](https://www.anchor-lang.com/docs/tokens/extensions#examples) ------------------------------------------------------------------------ The `anchor-spl` crate provides a [`token_2022_extensions`](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/spl/src/token_2022_extensions) module that contains helper functions and types for working with token extension instructions. You can find examples for how to work with Token Extensions in an Anchor program in this [program examples repository](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022) . Note that while the anchor-spl crate provides helper functions for working with Token Extensions, not all extension instructions have been fully implemented yet. You may need to manually implement CPI calls for some extension instructions. [Previous\ \ Transfer Tokens](https://www.anchor-lang.com/docs/tokens/basics/transfer-tokens) [Next\ \ Anchor References](https://www.anchor-lang.com/docs/references) ### On this page [What are Token Extensions?](https://www.anchor-lang.com/docs/tokens/extensions#what-are-token-extensions) [Examples](https://www.anchor-lang.com/docs/tokens/extensions#examples) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/tokens/extensions.mdx) --- # Anchor References Anchor References ================= Reference documentation for the Anchor framework. [### Account Types\ \ Anchor Account Type Examples](https://www.anchor-lang.com/docs/references/account-types) [### Account Constraints\ \ Anchor Account Constraints Examples](https://www.anchor-lang.com/docs/references/account-constraints) [### Anchor.toml Configuration\ \ Anchor workspace config reference documentation](https://www.anchor-lang.com/docs/references/anchor-toml) [### Anchor CLI\ \ Anchor CLI reference documentation](https://www.anchor-lang.com/docs/references/cli) [### Anchor Version Manager\ \ AVM reference documentation](https://www.anchor-lang.com/docs/references/avm) [### Account Space\ \ Reference guide for calculating account data size (bytes) requirements by Rust type](https://www.anchor-lang.com/docs/references/space) [### Rust to JS Type Conversion\ \ Reference for how Anchor converts between Rust and TypeScript types](https://www.anchor-lang.com/docs/references/type-conversion) [### Verifiable Builds\ \ Anchor - Verifiable Builds](https://www.anchor-lang.com/docs/references/verifiable-builds) [### Sealevel Attacks\ \ Anchor - Sealevel Attacks](https://www.anchor-lang.com/docs/references/security-exploits) [### Example Programs\ \ Example Anchor programs references](https://www.anchor-lang.com/docs/references/examples) [Previous\ \ Extensions](https://www.anchor-lang.com/docs/tokens/extensions) [Next\ \ Account Types](https://www.anchor-lang.com/docs/references/account-types) ### On this page No Headings [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/references/index.mdx) --- # Custom Errors [Additional Features](https://www.anchor-lang.com/docs/features) Custom Errors ============= Learn how to implement custom error handling in Anchor programs. All instruction handlers in Anchor programs return a custom `Result` type that allows you to handle successful execution with `Ok(T)` and error cases with `Err(Error)`. pub fn custom_instruction(ctx: Context) -> Result<()> { // --snip-- Ok(()) } The [`Result`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/lib.rs#L77) type in Anchor programs is a type alias that wraps the standard Rust `Result`. In this case, `T` represents the successful return type, while `E` is Anchor's custom `Error` type. pub type Result = std::result::Result; [Anchor Error](https://www.anchor-lang.com/docs/features/errors#anchor-error) ------------------------------------------------------------------------------ When an error occurs in an Anchor program, it returns a custom [`Error`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/error.rs#L277-L281) type defined as: #[derive(Debug, PartialEq, Eq)] pub enum Error { AnchorError(Box), ProgramError(Box), } The `Error` type in Anchor programs can be one of two variants: 1. [`ProgramErrorWithOrigin`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/error.rs#L389-L394) : Custom type that wraps a standard Solana [`ProgramError`](https://github.com/anza-xyz/agave/blob/v1.18.26/sdk/program/src/program_error.rs#L12-L66) type. These errors come from the `solana_program` crate. #[derive(Debug)] pub struct ProgramErrorWithOrigin { pub program_error: ProgramError, pub error_origin: Option, pub compared_values: Option, } 2. [`AnchorError`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/error.rs#L490-L497) : Errors defined by the Anchor framework. #[derive(Debug)] pub struct AnchorError { pub error_name: String, pub error_code_number: u32, pub error_msg: String, pub error_origin: Option, pub compared_values: Option, } An `AnchorError` can be thought of as having two categories: 1. Internal Anchor Errors - These are built-in errors included with the Anchor framework. They are defined in the [`ErrorCode`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/error.rs#L10-L275) enum. 2. Custom Program Errors - These are program specific errors that developers define to handle custom error cases. The `error_code_number` from an `AnchorError` has the following numbering scheme: | Error Code | Description | | --- | --- | | \>= 100 | Instruction error codes | | \>= 1000 | IDL error codes | | \>= 2000 | Constraint error codes | | \>= 3000 | Account error codes | | \>= 4100 | Misc error codes | | \= 5000 | Deprecated error code | | \>= 6000 | Starting point for custom user errors | [Usage](https://www.anchor-lang.com/docs/features/errors#usage) ---------------------------------------------------------------- Anchor provides a convenient way to define custom errors through the `error_code` attribute. The implementation details can be found [here](https://github.com/coral-xyz/anchor/blob/master/lang/syn/src/codegen/error.rs) . When you define an enum with the `error_code` attribute, Anchor automatically: * Assigns an error code starting from 6000 * Generates the necessary boilerplate for error handling * Enables the use of custom error messages via the `msg` attribute #[error_code] pub enum MyError { #[msg("My custom error message")] MyCustomError, #[msg("My second custom error message")] MySecondCustomError, } ### [err!](https://www.anchor-lang.com/docs/features/errors#err) To throw an error, use the [`err!`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/lib.rs#L735-L743) macro. The `err!` macro provides a convenient way to return custom errors from your program. Under the hood, `err!` uses the `error!` macro to construct `AnchorError`. The implementation can be found [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/error/src/lib.rs#L84-L116) . #[program] mod hello_anchor { use super::*; pub fn set_data(ctx: Context, data: MyAccount) - Result<()> { if data.data = 100 { return err!(MyError::DataTooLarge); } ctx.accounts.my_account.set_inner(data); Ok(()) } } #[error_code] pub enum MyError { #[msg("MyAccount may only hold data below 100")] DataTooLarge } ### [require!](https://www.anchor-lang.com/docs/features/errors#require) The [`require!`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/lib.rs#L525-L537) macro provides a more concise way to handle error conditions. It combines a condition check with returning an error if the condition is false. Here's how we can rewrite the previous example using `require!`: #[program] mod hello_anchor { use super::*; pub fn set_data(ctx: Context, data: MyAccount) - Result<()> { require!(data.data < 100, MyError::DataTooLarge); ctx.accounts.my_account.set_inner(data); Ok(()) } } #[error_code] pub enum MyError { #[msg("MyAccount may only hold data below 100")] DataTooLarge } Anchor provides several "require" macros for different validation needs. You can find the implementation of these macros [here](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/src/lib.rs) . | Macro | Description | | --- | --- | | `require!` | Ensures a condition is true, otherwise returns with the given error. | | `require_eq!` | Ensures two NON-PUBKEY values are equal. | | `require_neq!` | Ensures two NON-PUBKEY values are not equal. | | `require_keys_eq!` | Ensures two pubkeys values are equal. | | `require_keys_neq!` | Ensures two pubkeys are not equal. | | `require_gt!` | Ensures the first NON-PUBKEY value is greater than the second NON-PUBKEY value. | | `require_gte!` | Ensures the first NON-PUBKEY value is greater than or equal to the second NON-PUBKEY value. | [Example](https://www.anchor-lang.com/docs/features/errors#example) -------------------------------------------------------------------- Here's a simple example demonstrating how to define and handle custom errors in an Anchor program. The program below validates that an input amount falls within an acceptable range, showing how to: * Define custom error types with messages * Use the `require!` macro to check conditions and return errors ProgramClient lib.rs use anchor_lang::prelude::*; declare_id!("9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV"); #[program] pub mod custom_error { use super::*; pub fn validate_amount(_ctx: Context, amount: u64) - Result<()> { require!(amount >= 10, CustomError::AmountTooSmall); require!(amount <= 100, CustomError::AmountTooLarge); msg!("Amount validated successfully: {}", amount); Ok(()) } } #[derive(Accounts)] pub struct ValidateAmount {} #[error_code] pub enum CustomError { #[msg("Amount must be greater than or equal to 10")] AmountTooSmall, #[msg("Amount must be less than or equal to 100")] AmountTooLarge, } When a program error occurs, Anchor's TypeScript Client SDK returns a detailed [error response](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/error.ts#L51-L71) containing information about the error. Here's an example error response showing the structure and available fields: Error Response { errorLogs: [\ 'Program log: AnchorError thrown in programs/custom-error/src/lib.rs:11. Error Code: AmountTooLarge. Error Number: 6001. Error Message: Amount must be less than or equal to 100.'\ ], logs: [\ 'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV invoke [1]',\ 'Program log: Instruction: ValidateAmount',\ 'Program log: AnchorError thrown in programs/custom-error/src/lib.rs:11. Error Code: AmountTooLarge. Error Number: 6001. Error Message: Amount must be less than or equal to 100.',\ 'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV consumed 2153 of 200000 compute units',\ 'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV failed: custom program error: 0x1771'\ ], error: { errorCode: { code: 'AmountTooLarge', number: 6001 }, errorMessage: 'Amount must be less than or equal to 100', comparedValues: undefined, origin: { file: 'programs/custom-error/src/lib.rs', line: 11 } }, _programErrorStack: ProgramErrorStack { stack: [\ [PublicKey [PublicKey(9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV)]]\ ] } } For a more comprehensive example, you can also reference the [errors test program](https://github.com/coral-xyz/anchor/blob/master/tests/errors/programs/errors/src/lib.rs) in the Anchor repository. [Previous\ \ Dependency Free Composability](https://www.anchor-lang.com/docs/features/declare-program) [Next\ \ Emit Events](https://www.anchor-lang.com/docs/features/events) ### On this page [Anchor Error](https://www.anchor-lang.com/docs/features/errors#anchor-error) [Usage](https://www.anchor-lang.com/docs/features/errors#usage) [err!](https://www.anchor-lang.com/docs/features/errors#err) [require!](https://www.anchor-lang.com/docs/features/errors#require) [Example](https://www.anchor-lang.com/docs/features/errors#example) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/features/errors.mdx) --- # Emit Events [Additional Features](https://www.anchor-lang.com/docs/features) Emit Events =========== Learn how to emit events in Anchor programs using emit! and emit\_cpi! macros. [Examples](https://www.anchor-lang.com/docs/features/events#examples) ---------------------------------------------------------------------- Anchor provides two macros for emitting events in your programs: 1. `emit!()` - Emits events directly to program logs. This is the simpler, though program logs may be truncated by data providers in some cases 2. `emit_cpi!()` - Emits events through a Cross Program Invocation (CPI) by including the event data in the instruction data. The `emit_cpi()` approach was introduced an alternative to program logs, which can sometimes be truncated by data providers. While CPI instruction data is less likely to be truncated, this approach does incur additional compute costs from the Cross Program Invocation. For more robust solutions for events, consider geyser gRPC services by [Triton](https://docs.triton.one/project-yellowstone/dragons-mouth-grpc-subscriptions) or [Helius](https://docs.helius.dev/data-streaming/geyser-yellowstone) . ### [`emit`](https://www.anchor-lang.com/docs/features/events#emit) The [`emit!()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/event/src/lib.rs#L101-L109) macro provides a way to emit events through program logs. When called, it: 1. Uses the [`sol_log_data()`](https://github.com/anza-xyz/agave/blob/c2b350023ba849d1b33142592264aaa51fcb7f1e/sdk/program/src/log.rs#L115-L124) syscall to write the data to program logs 2. Encodes the event data as a [base64 string](https://github.com/anza-xyz/agave/blob/c2b350023ba849d1b33142592264aaa51fcb7f1e/program-runtime/src/stable_log.rs#L46-L61) prefixed with `Program Data:` To receive emitted events in your client application, use the [`addEventListener()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/event.ts#L74-L123) method. This method automatically [parses and decodes](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/event.ts#L232-L253) event data from the program logs. Example usage: ProgramClient lib.rs use anchor_lang::prelude::*; declare_id!("8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy"); #[program] pub mod event { use super::*; pub fn emit_event(_ctx: Context, input: String) -> Result<()> { emit!(CustomEvent { message: input }); Ok(()) } } #[derive(Accounts)] pub struct EmitEvent {} #[event] pub struct CustomEvent { pub message: String, } The following is the output of the program logs. The event data is base64 encoded as `Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE=`. Program Logs Log Messages: Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy invoke [1] Program log: Instruction: EmitEvent Program data: Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE= Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy consumed 1012 of 200000 compute units Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy success Ensure the RPC provider you use does not truncate the program logs from the transaction data. ### [`emit_cpi`](https://www.anchor-lang.com/docs/features/events#emit_cpi) The [`emit_cpi!()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/event/src/lib.rs#L155-L195) macro emits events through Cross Program Invocations (CPIs) to the program itself. The event data is encoded and included in the CPI's instruction data (instead of program logs). To emit events through CPIs, you need to enable the `event-cpi` feature in your program's `Cargo.toml`: Cargo.toml [dependencies] anchor-lang = { version = "0.31.1", features = ["event-cpi"] } Example usage: ProgramClient lib.rs use anchor_lang::prelude::*; declare_id!("2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1"); #[program] pub mod event_cpi { use super::*; pub fn emit_event(ctx: Context, input: String) -> Result<()> { emit_cpi!(CustomEvent { message: input }); Ok(()) } } #[event_cpi] #[derive(Accounts)] pub struct EmitEvent {} #[event] pub struct CustomEvent { pub message: String, } The [`event_cpi`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/event/src/lib.rs#L228-L237) attribute must be added to the `#[derive(Accounts)]` struct for the instruction that emits events using the `emit_cpi!()` macro. This attribute [automatically includes additional accounts](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/parser/accounts/event_cpi.rs#L28-L70) that are required for the self CPI. lib.rs #[event_cpi] #[derive(Accounts)] pub struct RequiredAccounts { // --snip-- } To get the emitted event data in your client application, you need to fetch the transaction using the transaction signature and parse the event data from the CPI instruction data. test.ts // 1. Fetch the full transaction data using the transaction signature const transactionData = await program.provider.connection.getTransaction( transactionSignature, { commitment: "confirmed" }, ); // 2. Extract the CPI (inner instruction) that contains the event data const eventIx = transactionData.meta.innerInstructions[0].instructions[0]; // 3. Decode the event data const rawData = anchor.utils.bytes.bs58.decode(eventIx.data); const base64Data = anchor.utils.bytes.base64.encode(rawData.subarray(8)); const event = program.coder.events.decode(base64Data); console.log(event); Below is an example transaction showing how event data appears in the transaction details. When using `emit_cpi!()`, the event data is encoded and included in the `data` field of an inner instruction (CPI). In the example transaction below, the encoded event data is `"data": "6AJcBqZP8afBKheoif1oA6UAiLAcqYr2RaR33pFnEY1taQp"` in the `innerInstructions` array. Transaction Data { "blockTime": 1735854530, "meta": { "computeUnitsConsumed": 13018, "err": null, "fee": 5000, "innerInstructions": [\ {\ "index": 0,\ "instructions": [\ {\ "accounts": [\ 1\ ],\ "data": "6AJcBqZP8afBKheoif1oA6UAiLAcqYr2RaR33pFnEY1taQp",\ "programIdIndex": 2,\ "stackHeight": 2\ }\ ]\ }\ ], "loadedAddresses": { "readonly": [], "writable": [] }, "logMessages": [\ "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 invoke [1]",\ "Program log: Instruction: EmitEvent",\ "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 invoke [2]",\ "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 consumed 5000 of 192103 compute units",\ "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 success",\ "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 consumed 13018 of 200000 compute units",\ "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 success"\ ], "postBalances": [\ 499999999999995000,\ 0,\ 1141440\ ], "postTokenBalances": [], "preBalances": [\ 500000000000000000,\ 0,\ 1141440\ ], "preTokenBalances": [], "rewards": [], "status": { "Ok": null } }, "slot": 3, "transaction": { "message": { "header": { "numReadonlySignedAccounts": 0, "numReadonlyUnsignedAccounts": 2, "numRequiredSignatures": 1 }, "accountKeys": [\ "4kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1",\ "2brZf9PQqEvv17xtbj5WNhZJULgVZuLZT6FgH1Cqpro2",\ "2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1"\ ], "recentBlockhash": "2QtnU35RXTo7uuQEVARYJgWYRYtbqUxWQkK8WywUnVdY", "instructions": [\ {\ "accounts": [\ 1,\ 2\ ],\ "data": "3XZZ984toC4WXCLkxBsLimpEGgH75TKXRJnk",\ "programIdIndex": 2,\ "stackHeight": null\ }\ ], "indexToProgramIds": {} }, "signatures": [\ "3gFbKahSSbitRSos4MH3cqeVv2FiTNaLCuWaLPo6R98FEbHnTshoYxopGcx74nFLqt1pbZK9i8dnr4NFXayrMndZ"\ ] } } Currently, event data emitted through CPIs cannot be directly subscribed to. To access this data, you must fetch the complete transaction data and manually decode the event information from the instruction data of the CPI. [Previous\ \ Custom Errors](https://www.anchor-lang.com/docs/features/errors) [Next\ \ Zero Copy](https://www.anchor-lang.com/docs/features/zero-copy) ### On this page [Examples](https://www.anchor-lang.com/docs/features/events#examples) [`emit`](https://www.anchor-lang.com/docs/features/events#emit) [`emit_cpi`](https://www.anchor-lang.com/docs/features/events#emit_cpi) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/features/events.mdx) --- # Mollusk [Testing Libraries](https://www.anchor-lang.com/docs/testing) Mollusk ======= Write tests for Solana programs in Rust using Mollusk. [Mollusk](https://github.com/anza-xyz/mollusk) is a lightweight test harness for Solana programs. It provides a simple interface for testing Solana program executions in a minified Solana Virtual Machine (SVM) environment. mollusk.process_and_validate_instruction( &instruction, // <-- Instruction to test &accounts, // <-- Account states &checks, // <-- Checks to run on the instruction result ); It does not create any semblance of a validator runtime, but instead provisions a program execution pipeline directly from lower-level SVM components. In summary, the main processor - `process_instruction` - creates minified instances of Agave's program cache, transaction context, and invoke context. It uses these components to directly execute the provided program's ELF using the BPF Loader. Because it does not use AccountsDB, Bank, or any other large Agave components, the harness is exceptionally fast. However, it does require the user to provide an explicit list of accounts to use, since it has nowhere to load them from. The test environment can be further configured by adjusting the compute budget, feature set, or sysvars. These configurations are stored directly on the test harness (the `Mollusk` struct), but can be manipulated through a handful of helpers. Four main API methods are offered: * `process_instruction`: Process an instruction and return the result. * `process_and_validate_instruction`: Process an instruction and perform a series of checks on the result, panicking if any checks fail. * `process_instruction_chain`: Process a chain of instructions and return the result. * `process_and_validate_instruction_chain`: Process a chain of instructions and perform a series of checks on each result, panicking if any checks fail. [Single Instructions](https://www.anchor-lang.com/docs/testing/mollusk#single-instructions) -------------------------------------------------------------------------------------------- Both `process_instruction` and `process_and_validate_instruction` deal with single instructions. The former simply processes the instruction and returns the result, while the latter processes the instruction and then performs a series of checks on the result. In both cases, the result is also returned. use { mollusk_svm::Mollusk, solana_sdk::{account::Account, instruction::{AccountMeta, Instruction}, pubkey::Pubkey}, }; let program_id = Pubkey::new_unique(); let key1 = Pubkey::new_unique(); let key2 = Pubkey::new_unique(); let instruction = Instruction::new_with_bytes( program_id, &[], vec![\ AccountMeta::new(key1, false),\ AccountMeta::new_readonly(key2, false),\ ], ); let accounts = vec![\ (key1, Account::default()),\ (key2, Account::default()),\ ]; let mollusk = Mollusk::new(&program_id, "my_program"); // Execute the instruction and get the result. let result = mollusk.process_instruction(&instruction, &accounts); To apply checks via `process_and_validate_instruction`, developers can use the `Check` enum, which provides a set of common checks. use { mollusk_svm::{Mollusk, result::Check}, solana_sdk::{ account::Account, instruction::{AccountMeta, Instruction}, pubkey::Pubkey system_instruction, system_program, }, }; let sender = Pubkey::new_unique(); let recipient = Pubkey::new_unique(); let base_lamports = 100_000_000u64; let transfer_amount = 42_000u64; let instruction = system_instruction::transfer(&sender, &recipient, transfer_amount); let accounts = [\ (\ sender,\ Account::new(base_lamports, 0, &system_program::id()),\ ),\ (\ recipient,\ Account::new(base_lamports, 0, &system_program::id()),\ ),\ ]; let checks = vec![\ Check::success(),\ Check::compute_units(system_processor::DEFAULT_COMPUTE_UNITS),\ Check::account(&sender)\ .lamports(base_lamports - transfer_amount)\ .build(),\ Check::account(&recipient)\ .lamports(base_lamports + transfer_amount)\ .build(),\ ]; Mollusk::default().process_and_validate_instruction( &instruction, &accounts, &checks, ); Note: `Mollusk::default()` will create a new `Mollusk` instance without adding any provided BPF programs. It will still contain a subset of the default builtin programs. For more builtin programs, you can add them yourself or use the `all-builtins` feature. [Instruction Chains](https://www.anchor-lang.com/docs/testing/mollusk#instruction-chains) ------------------------------------------------------------------------------------------ Both `process_instruction_chain` and `process_and_validate_instruction_chain` deal with chains of instructions. The former processes each instruction in the chain and returns the final result, while the latter processes each instruction in the chain and then performs a series of checks on each result. In both cases, the final result is also returned. use { mollusk_svm::Mollusk, solana_sdk::{account::Account, pubkey::Pubkey, system_instruction}, }; let mollusk = Mollusk::default(); let alice = Pubkey::new_unique(); let bob = Pubkey::new_unique(); let carol = Pubkey::new_unique(); let dave = Pubkey::new_unique(); let starting_lamports = 500_000_000; let alice_to_bob = 100_000_000; let bob_to_carol = 50_000_000; let bob_to_dave = 50_000_000; mollusk.process_instruction_chain( &[\ system_instruction::transfer(&alice, &bob, alice_to_bob),\ system_instruction::transfer(&bob, &carol, bob_to_carol),\ system_instruction::transfer(&bob, &dave, bob_to_dave),\ ], &[\ (alice, system_account_with_lamports(starting_lamports)),\ (bob, system_account_with_lamports(starting_lamports)),\ (carol, system_account_with_lamports(starting_lamports)),\ (dave, system_account_with_lamports(starting_lamports)),\ ], ); Just like with `process_and_validate_instruction`, developers can use the `Check` enum to apply checks via `process_and_validate_instruction_chain`. Notice that `process_and_validate_instruction_chain` takes a slice of tuples, where each tuple contains an instruction and a slice of checks. This allows the developer to apply specific checks to each instruction in the chain. The result returned by the method is the final result of the last instruction in the chain. use { mollusk_svm::{Mollusk, result::Check}, solana_sdk::{account::Account, pubkey::Pubkey, system_instruction}, }; let mollusk = Mollusk::default(); let alice = Pubkey::new_unique(); let bob = Pubkey::new_unique(); let carol = Pubkey::new_unique(); let dave = Pubkey::new_unique(); let starting_lamports = 500_000_000; let alice_to_bob = 100_000_000; let bob_to_carol = 50_000_000; let bob_to_dave = 50_000_000; mollusk.process_and_validate_instruction_chain( &[\ (\ // 0: Alice to Bob\ &system_instruction::transfer(&alice, &bob, alice_to_bob),\ &[\ Check::success(),\ Check::account(&alice)\ .lamports(starting_lamports - alice_to_bob) // Alice pays\ .build(),\ Check::account(&bob)\ .lamports(starting_lamports + alice_to_bob) // Bob receives\ .build(),\ Check::account(&carol)\ .lamports(starting_lamports) // Unchanged\ .build(),\ Check::account(&dave)\ .lamports(starting_lamports) // Unchanged\ .build(),\ ],\ ),\ (\ // 1: Bob to Carol\ &system_instruction::transfer(&bob, &carol, bob_to_carol),\ &[\ Check::success(),\ Check::account(&alice)\ .lamports(starting_lamports - alice_to_bob) // Unchanged\ .build(),\ Check::account(&bob)\ .lamports(starting_lamports + alice_to_bob - bob_to_carol) // Bob pays\ .build(),\ Check::account(&carol)\ .lamports(starting_lamports + bob_to_carol) // Carol receives\ .build(),\ Check::account(&dave)\ .lamports(starting_lamports) // Unchanged\ .build(),\ ],\ ),\ (\ // 2: Bob to Dave\ &system_instruction::transfer(&bob, &dave, bob_to_dave),\ &[\ Check::success(),\ Check::account(&alice)\ .lamports(starting_lamports - alice_to_bob) // Unchanged\ .build(),\ Check::account(&bob)\ .lamports(starting_lamports + alice_to_bob - bob_to_carol - bob_to_dave) // Bob pays\ .build(),\ Check::account(&carol)\ .lamports(starting_lamports + bob_to_carol) // Unchanged\ .build(),\ Check::account(&dave)\ .lamports(starting_lamports + bob_to_dave) // Dave receives\ .build(),\ ],\ ),\ ], &[\ (alice, system_account_with_lamports(starting_lamports)),\ (bob, system_account_with_lamports(starting_lamports)),\ (carol, system_account_with_lamports(starting_lamports)),\ (dave, system_account_with_lamports(starting_lamports)),\ ], ); It's important to understand that instruction chains _should not_ be considered equivalent to Solana transactions. Mollusk does not impose constraints on instruction chains, such as loaded account keys or size. Developers should recognize that instruction chains are primarily used for testing program execution. [Benchmarking Compute Units](https://www.anchor-lang.com/docs/testing/mollusk#benchmarking-compute-units) ---------------------------------------------------------------------------------------------------------- The Mollusk Compute Unit Bencher can be used to benchmark the compute unit usage of Solana programs. It provides a simple API for developers to write benchmarks for their programs, which can be checked while making changes to the program. A markdown file is generated, which captures all of the compute unit benchmarks. If a benchmark has a previous value, the delta is also recorded. This can be useful for developers to check the implications of changes to the program on compute unit usage. use { mollusk_svm_bencher::MolluskComputeUnitBencher, mollusk_svm::Mollusk, /* ... */ }; // Optionally disable logging. solana_logger::setup_with(""); /* Instruction & accounts setup ... */ let mollusk = Mollusk::new(&program_id, "my_program"); MolluskComputeUnitBencher::new(mollusk) .bench(("bench0", &instruction0, &accounts0)) .bench(("bench1", &instruction1, &accounts1)) .bench(("bench2", &instruction2, &accounts2)) .bench(("bench3", &instruction3, &accounts3)) .must_pass(true) .out_dir("../target/benches") .execute(); The `must_pass` argument can be provided to trigger a panic if any defined benchmark tests do not pass. `out_dir` specifies the directory where the markdown file will be written. Developers can invoke this benchmark test with `cargo bench`. They may need to add a bench to the project's `Cargo.toml`. [[bench]] name = "compute_units" harness = false The markdown file will contain entries according to the defined benchmarks. | Name | CUs | Delta | | ------ | ----- | ------ | | bench0 | 450 | -- | | bench1 | 579 | -129 | | bench2 | 1,204 | +754 | | bench3 | 2,811 | +2,361 | [Previous\ \ LiteSVM](https://www.anchor-lang.com/docs/testing/litesvm) [Next\ \ Features](https://www.anchor-lang.com/docs/features) ### On this page [Single Instructions](https://www.anchor-lang.com/docs/testing/mollusk#single-instructions) [Instruction Chains](https://www.anchor-lang.com/docs/testing/mollusk#instruction-chains) [Benchmarking Compute Units](https://www.anchor-lang.com/docs/testing/mollusk#benchmarking-compute-units) [Edit on GitHub](https://github.com/coral-xyz/anchor/blob/master/docs/content/docs/testing/mollusk.mdx) --- # Anchor.toml Configuration [Program Development](https://www.anchor-lang.com/docs/references) Anchor.toml Configuration ========================= Anchor workspace config reference documentation [provider (required)](https://www.anchor-lang.com/docs/references/anchor-toml#provider-required) ------------------------------------------------------------------------------------------------- A wallet and cluster that are used for all commands. Example: [provider] cluster = "localnet" # The cluster used for all commands. wallet = "~/.config/solana/id.json" # The keypair used for all commands. [scripts (required for testing)](https://www.anchor-lang.com/docs/references/anchor-toml#scripts-required-for-testing) ----------------------------------------------------------------------------------------------------------------------- Scripts that can be run with `anchor run