-
Anchor is Solana's Sealevel runtime framework, providing several convenient developer tools for writing programs.
-
Anchor writes various boilerplates, such as (de)serialization of accounts and instruction data.
-
Anchor handles security checks and keeps them separated from business logic.
- Install Anchor using these instructions:
cargo install --git https://github.com/coral-xyz/anchor avm --locked --force
avm install latest
avm use latest
- Verify the installation with:
anchor --version
- An Anchor program consists of three parts:
- The
program
module: where the logic is written. - The account structs, marked with
#[derive(Accounts)]
, where accounts are validated. - The
declare_id
macro, creates anID
field to store the address of the program.
- The
- Where you define the business logic by writing functions that clients or other programs can call:
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
if ctx.accounts.token_account.amount > 0 {
ctx.accounts.my_account.data = data;
}
Ok(())
}
}
- Each endpoint takes a
Context
type as its first argument, so it can access:- the accounts (
ctx.accounts
) - the program_id (
ctx.program_id
) of the executing program - remaining accounts (
ctx.remaining_accounts
)
- the accounts (
- If a function requires instruction data, it can be added through arguments to the function after the context argument.
-
Define which accounts an instruction expects, and their constraints.
-
There are two constructs:
Types
: have a specific use case.Account
: when an instruction is the deserialized data of the account. It's a generic overT
, created to store data.
-
The
#[account]
attribute sets the owner of that data to thedeclare_id
.Account
verifies that the owner ofmy_account
equalsdeclare_id
.
#[account]
#[derive(Default)]
pub struct MyAccount {
data: u64
}
#[derive(Accounts)]
pub struct SetData<'info> {
#[account(mut)]
pub my_account: Account<'info, MyAccount>
}
-
Account types are not dynamic enough to handle all the security checks that the program requires.
-
Constraints can be added through:
#[account(<constraints>)]
pub account: AccountType
-
Anchor programs have two types of errors:
AnchorErrors
: divided into anchor internal errors and custom errors- non-anchor errors
-
You can use the
require
macro to simplify writing errors.
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context<SetData>, 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
}
-
CPIs enable the composability of Solana programs, allowing developers to use and build on existing programs' instructions.
-
To execute CPIs, use
invoke
orinvoke_signed
from thesolana_program
crate:
// Used when there are not signatures for PDAs needed
pub fn invoke(
instruction: &Instruction,
account_infos: &[AccountInfo<'_>]
) -> ProgramResult
// Used when a program must provide a 'signature' for a PDA, hence the signer_seeds parameter
pub fn invoke_signed(
instruction: &Instruction,
account_infos: &[AccountInfo<'_>],
signers_seeds: &[&[&[u8]]]
) -> ProgramResult
- To make a CPI, you must specify and construct an instruction on the program being invoked and supply a list of accounts necessary for that instruction.
- If a PDA is required as a signed, the
signers_seeds
must also be provided withinvoke_signed
.
- If a PDA is required as a signed, the
-
CPIs extend the privileges of the caller to the callee.
-
Privilege extension can be dangerous. If a malicious program creates a CPI, the program has the same privileges as the caller.
-
Anchor protects your code from CPIs to malicious programs by the
Program<'info, T>
type check being given to the account is the expected programT
.
- To initialize a new project (anchor workspace), run:
anchor init <workspace-name>
- The following files will be created:
.anchor
: includes the most recent program logs and a local ledger for testing.app/
: an empty folder that can be used to hold the front end if you use a mono repo.programs/
: initially contains a program with the workspace name, and alib.rs
.tests/
migrations/
:you can save your deployment and migration scripts.Anchor.toml
: this file configures workspace wide settings. Initially, it configures:- the address of your programs on localnet (
[programs.localnet]
) - a registry your program can be pushed to (
[registry]
) - a provider which can be used in your tests (
[provider]
) - scripts that anchor executes for you (
[scripts]
).
- the address of your programs on localnet (
- List the current program id:
anchor keys list
- Learn how cross-program instructions work on Anchor through the backend's demo 2.