⚓ Solana Sealevel Framework

Last update: May 23, 2022

Anchor

Build Status Docs Chat License

Anchor is a framework for Solana's Sealevel runtime providing several convenient developer tools.

  • Rust eDSL for writing Solana programs
  • IDL specification
  • TypeScript package for generating clients from IDL
  • CLI and workspace management for developing complete applications

If you're familiar with developing in Ethereum's Solidity, Truffle, web3.js or Parity's Ink!, then the experience will be familiar. Although the DSL syntax and semantics are targeted at Solana, the high level flow of writing RPC request handlers, emitting an IDL, and generating clients from IDL is the same.

Getting Started

For a quickstart guide and in depth tutorials, see the guided documentation. To jump straight to examples, go here. For the latest Rust API documentation, see docs.rs.

Packages

Package Description Version Docs
anchor-lang Rust primitives for writing programs on Solana Crates.io Docs.rs
anchor-spl CPI clients for SPL programs on Solana crates Docs.rs
anchor-client Rust client for Anchor programs crates Docs.rs
@project-serum/anchor TypeScript client for Anchor programs npm Docs

Note

  • Anchor is in active development, so all APIs are subject to change.
  • This code is unaudited. Use at your own risk.

Examples

Build stateful programs on Solana by defining a state struct with associated methods. Here's a classic counter example, where only the designated authority can increment the count.

#[program]
mod counter {

    #[state]
    pub struct Counter {
      authority: Pubkey,
      count: u64,
    }

    pub fn new(ctx: Context<Auth>) -> Result<Self> {
        Ok(Self {
            auth: *ctx.accounts.authority.key
        })
    }

    pub fn increment(&mut self, ctx: Context<Auth>) -> Result<()> {
        if &self.authority != ctx.accounts.authority.key {
            return Err(ErrorCode::Unauthorized.into());
        }

        self.count += 1;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct Auth<'info> {
    #[account(signer)]
    authority: AccountInfo<'info>,
}

#[error]
pub enum ErrorCode {
    #[msg("You are not authorized to perform this action.")]
    Unauthorized,
}

Additionally, one can utilize the full power of Solana's parallel execution model by keeping the program stateless and working with accounts directly. The above example can be rewritten as follows.

use anchor::prelude::*;

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

    pub fn initialize(ctx: Context<Initialize>, authority: Pubkey) -> Result<()> {
        let counter = &mut ctx.accounts.counter;

        counter.authority = authority;
        counter.count = 0;

        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;

        counter += 1;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init)]
    pub counter: ProgramAccount<'info, Counter>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut, has_one = authority)]
    pub counter: ProgramAccount<'info, Counter>,
    #[account(signer)]
    pub authority: AccountInfo<'info>,
}

#[account]
pub struct Counter {
    pub authority: Pubkey,
    pub count: u64,
}

#[error]
pub enum ErrorCode {
    #[msg("You are not authorized to perform this action.")]
    Unauthorized,
}

Due to the fact that account sizes on Solana are fixed, some combination of the above is often required. For example, one can store store global state associated with the entire program in the #[state] struct and local state assocated with each user in individual #[account] structs.

For more, see the examples directory.

License

Anchor is licensed under Apache 2.0.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Anchor by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.

GitHub

https://github.com/project-serum/anchor
Comments
  • 1. unable to use anchor on arm

    Description

    When trying to use anchor on a m1 based mac I get the below error:

    ❯ anchor     
    [1]    97137 illegal hardware instruction  anchor
    

    Not sure if this is because of a dependency but its odd because rust is emulated to use x86 instructions.

    Reviewed by marbar3778 at 2021-02-27 10:22
  • 2. devnet deploy error: unrecognized signer source

    I created setup project using anchor init testproject --javascript in $HOME/solana project directory. After:

    1. setting up to devnet using solana config set --url devnet
    2. changing localnet to devnet in Anchor.toml
    3. changing program id in lib.rs and Anchor.toml file same as solana address -k target/deploy/testproject-keypair.json
    4. anchor build --> success
    5. anchor deploy --> error

    anchor deploy error:

    Deploying workspace: https://api.devnet.solana.com
    Upgrade authority: $HOME/.config/solana/id.json
    Deploying program "testproject"...
    Program path: $HOME/solana project/target/deploy/testproject.so...
    error: Invalid value for '--program-id <PROGRAM_ID>': unrecognized signer source
    There was a problem deploying: Output { status: ExitStatus(ExitStatus(256)), stdout: "", stderr: "" }.
    

    I have followed same steps as above but created project in $HOME/solana_project directory, anchor deploy worked properly.

    Observation: project path containing space could have caused the whole issue.

    Analysis: In the solana program deploy.... command here for 2nd project command will be solana program deploy ... --program-id ... $HOME/solana_project/... for 1st project command will be solana program deploy ... --program-id ... $HOME/solana project/... a space in the whole command is causing the issue similar to how a copy/move command errors out in linux

    Reviewed by shivam-agarwal-0 at 2021-11-10 19:01
  • 3. Add support for `anchor idl fetch` to work outside anchor workspace

    Context

    Closes #1453 (Refer to this issue for context)

    Changes

    1. anchor idl fetch can now be run outside an anchor workspace.
    2. If it is run outside workspace, provider.cluster option has to be provided.
    Reviewed by NBNARADHYA at 2022-02-22 22:29
  • 4. Issues w/ anchor test

    Hey there! On anchor-cli 0.18.0.

    Trying to run anchor test but when I do so, I get hit with:

    Failed to run test: ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts: No such file or directory (os error 2).

    So, I then did npm install ts-mocha -g to see if that would change anything.

    Running the test again, I get

    node: --dns-result-order= is not allowed in NODE_OPTIONS.

    Just running a boilerplate hello-world project from the docs via anchor init helloworld.

    I also tried doing anchor init helloworld --javascript, then do anchor test, and still get: node: --dns-result-order= is not allowed in NODE_OPTIONS.

    Reviewed by farzaa at 2021-10-27 23:43
  • 5. Anchor Events Are Extremely Compute Intensive When Used Without Maximal Compiler Optimizations

    Overview

    With the default compiler optimizations, logging the same information through emit! is approximately 2x more expensive in compute units, than it is to directly use msg!.

    When using maximal compiler optimizations as follows, the cost increase is drastically reduced, but is still more expensive.

    lto = "fat"
    codegen-units = 1
    [profile.release.build-override]
    opt-level = 3
    incremental = false
    codegen-units = 1
    

    While this can solve compute unit usage issues within your own programs, it still leaves programs at risk of reaching compute unit limits when making CPI to third-party programs that emit events, without these compiler optimizations.

    As it stands this is more of an edge-case issue, however if the current event system is kept in place I think once more programs are deployed onto Solana, and there is more interconnectivity between programs, this will probably start to become a real issue.

    Proposed Solution - Avoid Borsh Serialization And Base64 Encoding Completely

    Personally speaking I think the best option is to remove serialization and encoding of events, and use proc macros to format the event into a JSON string which is what gets logged. This has the added bonus of being human readable on block explorers.

    Alternative Solutions

    • update anchor docs to recommend using the aforementioned compiler optimizations when using anchor events
    • when running anchor init add the aforementioned compiler optimizations to the default workspace file.

    Optimize The Process Of Emitting Events

    Not exactly sure what this would look like, but there's probably something that can be done. At a quick glance, changing this function to preallocate the vector entirely would help, but im not sure if this is possible.

    Add Compiler Optimizations To Default Workspace File Generated By Anchor

    Reviewed by bonedaddy at 2021-10-10 04:03
  • 6. npm: Invalid anchor version

    npm package 0.18.0 have invalid anchor binary :disappointed:

    $ npm ls @project-serum/anchor-cli
    [email protected] /home/kirill/projects/x-project
    └── @project-serum/[email protected]
    
    $ npx anchor --version
    Package binary version is not correct. Expected "anchor-cli 0.18.0", found "anchor-cli 0.17.0".
    Trying globally installed anchor.
    Failed to get version of global binary: Error: spawnSync undefined/anchor ENOENT
    
    Reviewed by fanatid at 2021-10-25 10:08
  • 7. anchor provider depends on fs module

    Bundling the anchor package for usage inside a browser-based react app is currently causing build failures. These can be circumvented by configuring webpack, but I think this kind of solutions is far from ideal, as it increases the friction for a first time anchor user. What would we need to change, to prevent the following issue?

    I am using roughly the following code to create a new Program inside a react app

    import * as anchor from '@project-serum/anchor'
    import poolIdl from '../idls/ido_pool'
    
    const provider = new anchor.Provider(connection, wallet, anchor.Provider.defaultOptions())
    const programId = new anchor.web3.PublicKey('E5s3D6B3PJinuB9kb3dicxfi3qUNLUGX6hoPawhbqagt')
    const program = new anchor.Program(poolIdl, programId, provider);
    

    This will result in the following error:

    ./node_modules/@project-serum/anchor/dist/esm/provider.js:87:0
    Module not found: Can't resolve 'fs'
    null
    

    I found a common workaround for this issue in this stack overflow post: https://stackoverflow.com/questions/57161839/module-not-found-error-cant-resolve-fs-in

    Reviewed by mschneider at 2021-05-05 11:46
  • 8. ts: Program upgrade event crashes existing listeners

    So, we have custom event inside our program and appropriate listener in our client. Problem is that when we upgrade our program (or run anchor test) our client program crashes and gives us following error:

    /Users/zeke/WebstormProjects/marketplace-server/node_modules/@project-serum/anchor/src/program/event.ts:266
          throw new Error(`Could not find program invocation log line`);
                ^
    Error: Could not find program invocation log line
        at new ExecutionContext (/Users/zeke/WebstormProjects/marketplace-server/node_modules/@project-serum/anchor/src/program/event.ts:266:13)
        at EventParser.parseLogs (/Users/zeke/WebstormProjects/marketplace-server/node_modules/@project-serum/anchor/src/program/event.ts:177:23)
        at Object.callback (/Users/zeke/WebstormProjects/marketplace-server/node_modules/@project-serum/anchor/src/program/event.ts:103:27)
        at Connection._wsOnLogsNotification (/Users/zeke/WebstormProjects/marketplace-server/node_modules/@solana/web3.js/src/connection.ts:4360:13)
        at Client.emit (/Users/zeke/WebstormProjects/marketplace-server/node_modules/eventemitter3/index.js:181:35)
        at /Users/zeke/WebstormProjects/marketplace-server/node_modules/rpc-websockets/dist/lib/client.js:446:22
        at processTicksAndRejections (node:internal/process/task_queues:96:5)
    error Command failed with exit code 1.
    
    

    So when we upgrade program, following regex fails /^Program (.*) invoke.*$/g, because log starts with: Upgraded program **** and causes our client to crash.

    Class name is ExecutionContext where this regex is used. We can fix it by simply wrapping creation of this class in try/catch, but there could be better solutions, because we don't want to change it inside node_modules

    Our client code:

     program.addEventListener("ListingClosed", (event: ListingClosedEvent) => {
            console.log('event', event.accountAddress.toBase58())
     });
    
    Reviewed by dfl-zeke at 2022-03-25 21:02
  • 9. IDL Doc Field

    Adds a new, optional doc field to several of the IDL structs. The program module, instruction functions, and account structs are searched for inner doc comments (this is intended to minimize intrusion on existing programs, which likely use outer doc comments on those elements). IxArg and IdlField also will grab their associated doc comment.

    The doc field is not included in the IDL JSON in cases when it parses to None.

    Todo:

    • Someone already got close with adding a docs field to the AccountField, it just needs wiring up.
    • Considering a command-line flag to suppress inclusion of doc fields in anchor idl parse.
    Reviewed by ebrightfield at 2022-03-06 18:42
  • 10. Error redesign

    closes #798

    Changes:

    • adds Error enum (AnchorError or ProgramErrorWithOrigin)
    • adds type Result<T> = Result<T, Error> thats to be used instead of ProgramResult
    • adds error! macro that creates AnchorError with source info and wraps it inside an Error
    • adds err! macro that expands into Err(error!(#error_code))
    • adds source! macro that can be used to enrich ProgramErrors with Source information
    • renames #[error] to #[error_code]
    • adjust ts library so it can parse custom errors from real tx instead of just simulated ones
    Reviewed by paul-schaaf at 2022-02-17 17:43
  • 11. potential pitfall: PDA constraint check doesn't validate bump against `findProgramAddress`

    Suppose we have the following accounts struct for some kind of initialization instruction in a program:

    #[derive(Accounts)]
    #[instruction(authority_bump: u8)]
    pub struct Initialize<'info> {
        #[account(init, payer=payer, space = <space>)]
        state: Account<'info, State>,
    
        #[account(
            seeds = [
                state.key().as_ref()
            ],
            bump = authority_bump,
        )]
        authority: AccountInfo<'info>,
    
        payer: Signer<'info>,
        system_program: Program<'info, System>,
    }
    

    and suppose the state address is such that the authority PDA can be derived with say 254 and 250 bump seeds.

    The #[account( seeds = [ state.key().as_ref() ], bump = authority_bump )] constraint check will successfully validate for authority addresses derived from any of these seeds.

    I believe this is dangerous because most users will assume that the check will assert that the bump is the same as the one from calling findProgramAddress. This would break frontend client assumptions because now the authority is not "stateless" anymore as the clients can't deterministically derive it by using findProgramAddress but would first have to fetch the correct bump seed from the state account.

    I think the default should be that the #[account( seeds = [ state.key().as_ref() ], bump = authority_bump )] constraint check validates the seed against findProgramAddress as this is the most common use case and what most developers will expect. For the cases where other bump seeds can be valid there we could have a flag (e.g. any_pda_is_valid):

        #[account(
            seeds = [
                state.key().as_ref()
            ],
            bump = authority_bump,
            any_pda_is_valid,
        )]
    
    Reviewed by kklas at 2021-11-05 14:56
  • 12. Fix not being able to import Wallet interface

    interface Wallet wasn't getting exported despite the Provider using it.

    Also gave workspace a type Record<string, Program>. It doesn't specify the specific IDLs of each program however.

    Reviewed by Tristyn at 2022-05-23 11:16
  • 13. cli: Allow passing arguments to an underlying script

    Sometimes it is desirable to run only specific test cases. For this it is required to let the underlying script know which tests should be run. For example, given this Anchor.toml

    [scripts]
    mocha = "yarn run ts-mocha -t 1000000"
    

    It is desirable to be able to run:

    $ anchor run mocha -- ./tests/one-specific-test.ts
    
    Reviewed by sushi-shi at 2022-05-21 15:32
  • 14. BUG [TypeScript] Program problem with vector of defined type

    Hello, the problem is in the last line. I believe there's a problem in having vectors of defined types.

    type HelpMe = {
        "version": "1.0.0",
        "name": "tester",
        "instructions": [],
        "accounts": [
          {
            "name": "test",
            "type": {
              "kind": "struct",
              "fields": [
                {
                  "name": "vecExample",
                  "type":{
                    "vec": {
                      "defined": "TestDefined"
                    }
                  }
                }
              ]
            }
          },
        ],
        "types": [{
          "name": "TestDefined",
          "type": {
            "kind": "struct",
            "fields": [
              {
                "name": "testField",
                "type": "u8"
              }
            ]
          }
        }],
        "events": [],
        "errors": []
      };
    
      const testProgram = new Program<HelpMe>(
        "who cares about this IDL" as any,
        "",
        anchor.getProvider(),
      );
    
      const test = await testProgram.account.test.fetch("a");
      test.vecExample // The problem is here, shouldn't vecExample be of type TestDefined[] ? Instead it is of type 'unknown'
    

    Before anyone asks, I manually created the type HelpMe. BUT it is a minimal example to reproduce the error I was seeing from an Anchor generated type.

    Reviewed by tallalnparis4ev at 2022-05-21 12:38
  • 15. The declared program id does not match the actual program id

    I am trying to familiarize myself with the Anchor ecosystem by following the instructions here. I am running into an error when I reach the Generating a Client section.

    My lib.rs is completely unchanged

    use anchor_lang::prelude::*;
    
    declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
    
    #[program]
    pub mod my_project {
        use super::*;
    
        pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
            Ok(())
        }
    }
    
    #[derive(Accounts)]
    pub struct Initialize {}
    

    I've successfully run anchor build and anchor deploy ...

    ❯ anchor deploy
    Deploying workspace: http://localhost:8899
    Upgrade authority: /Users/matteosantamaria/.config/solana/id.json
    Deploying program "my_project"...
    Program path: /Users/matteosantamaria/my_project/target/deploy/unnamed.so...
    Program Id: 2uAaYZESqWuvLfPaL9pwUY7g5cWY6oz6NEshreKvMDVD
    
    Deploy success
    

    so my client.js looks like

    const anchor = require("@project-serum/anchor");
    
    // Configure the local cluster.
    anchor.setProvider(anchor.AnchorProvider.local());
    
    async function main() {
      // #region main
      // Read the generated IDL.
      const idl = JSON.parse(
        require("fs").readFileSync("./target/idl/my_project.json", "utf8")
      );
    
      // Address of the deployed program.
      const programId = new anchor.web3.PublicKey("2uAaYZESqWuvLfPaL9pwUY7g5cWY6oz6NEshreKvMDVD");
    
      // Generate the program client from IDL.
      const program = new anchor.Program(idl, programId);
    
      // Execute the RPC.
      await program.rpc.initialize();
      // #endregion main
    }
    
    console.log("Running client.");
    main().then(() => console.log("Success"));
    

    but when I run

    ❯ ANCHOR_WALLET=/Users/matteosantamaria/.config/solana/id.json node client.js
    

    I get errors complaining that "The declared program id does not match the actual program id". What am I doing wrong here?

    Reviewed by matteosantama at 2022-05-20 23:14
  • 16. nightly builds for anchor cli and ts

    Can we have nightly builds for the anchor cli and ts client packages? I want to test some unreleased features but it's kinda difficult when I have to reference manually built packages especially within a CI environment.

    A nightly channel on the anchor-cli and anchor npm packages would work, or at least a tarball published on github that I can point to from package.json.

    Reviewed by kklas at 2022-05-20 21:56
  • 17. Allow the payer in the attribute `#[account(init, payer)]` to be a PDA

    An instruction of my program creates a TokenAccount using #[account(init, payer = ...)]. But I don't want the transaction sender (usually a user) to pay for the account rent. So I use a PDA (derived from my program) that has a certain amount of SOL to pay for the account rent.

    I need the payer in #[account(init, payer = ...)] to be a PDA derived from my program but the macro only supports setting seeds for the account. So I have to manually use invoke_signed with payer seeds and account seeds to create and initialize the TokenAccount.

    It's very nice if there are options for setting seeds for the payer.

    Reviewed by phqb at 2022-05-20 10:35
Demonstrates Solana data account versioning used in supporting the Solana Cookbook article: Account Data Versioning
Demonstrates Solana data account versioning used in supporting the Solana Cookbook article: Account Data Versioning

versioning-solana This repo demonstrates ONE rudimentary way to upgrade/migrate account data changes with solana program changes. What is data version

Feb 12, 2022
A framework for creating PoC's for Solana Smart Contracts in a painless and intuitive way

Solana PoC Framework DISCLAIMER: any illegal usage of this framework is heavily discouraged. Most projects on Solana offer a more than generous bug bo

May 18, 2022
The Voting example based on MoonZoon and Solana + Anchor framework.
The Voting example based on MoonZoon and Solana + Anchor framework.

The Voting example based on MoonZoon and Solana + Anchor framework.

May 4, 2022
Metaplex is a protocol built on top of Solana that allows: Creating/Minting non-fungible tokens;
Metaplex is a protocol built on top of Solana that allows: Creating/Minting non-fungible tokens;

Metaplex is a protocol built on top of Solana that allows: Creating/Minting non-fungible tokens; Starting a variety of auctions for primary/secondary

May 24, 2022
⛏ An open protocol for launching liquidity mining programs on Solana.
⛏ An open protocol for launching liquidity mining programs on Solana.

⛏ Quarry An open protocol for launching liquidity mining programs on Solana. Background Quarry was built with the intention of helping more Solana pro

May 19, 2022
Generate Nice Solana Address By Template

Yes, I know about GPU generators. https://smith-mcf.medium.com/solana-vanity-address-using-gpus-5a68ad94d1d4 ./solana-nice-address --help solana-nice-

Apr 16, 2022
sandbox to play around numerous functionalities on Solana

Solana Sandbox This sandbox is for verifying smart contracts(programs) implemented on Solana for a self-study purpose. Programs Currently implemented

May 11, 2022
Solana Escrow Program written by RUST.

Environment Setup Install Rust from https://rustup.rs/ Install Solana from https://docs.solana.com/cli/install-solana-cli-tools#use-solanas-install-to

Mar 10, 2022
A suite of programs for Solana key management and security.
A suite of programs for Solana key management and security.

?? goki Goki is a suite of programs for Solana key management and security. It currently features: Goki Smart Wallet: A wallet loosely based on the Se

May 14, 2022
Testing a smart contract on the Solana blockchain

Environment Setup Install Rust from https://rustup.rs/ Install Solana from https://docs.solana.com/cli/install-solana-cli-tools#use-solanas-install-to

Oct 25, 2021
Solana NFT generative artwork program

resin Solana NFT generative artwork program Installation Depends on imagemagick for art generation, which can be installed here: https://imagemagick.o

Apr 27, 2022
Simple template for building smart contract(Rust) and RPC Client(web3.js) on Solana (WIP) ⛏👷🚧⚠️
Simple template for building smart contract(Rust) and RPC Client(web3.js) on Solana (WIP) ⛏👷🚧⚠️

Solana BPF Boilerplate Simple template for building smart contract(Rust) and RPC Client(web3.js) on Solana This boilerplate provides the following. Si

Jan 30, 2022
Examples of Solana on-chain programs

spl-examples List of Solana on-chain programs which demonstrate different aspects of Solana architecture. 01__state It's a counter program. Each user

May 26, 2022
🧑‍✈ Version control and key management for Solana programs.

captain ??‍✈️ Version control and key management for Solana programs. Automatic versioning of program binaries based on Cargo Separation of deployer a

Mar 1, 2022
Synchronized shadow state of Solana programs available for off-chain processing.

Solana Shadow The Solana Shadow crate adds shadows to solana on-chain accounts for off-chain processing. This create synchronises all accounts and the

May 21, 2022
Battery-included Solana/Anchor project skeleton.

Anchor Skeleton Battery-included Solana/Anchor project skeleton. Features Rust test only: All tests (integration, unit) are written in Rust, so the co

Feb 23, 2022
A solana program designed to mint Metaplex compliant NFTs.

Solana Minter My program used to mint Amoebits & Amoebit Minis. I wrote it from scratch using the hello-world program as an example & base. Features C

May 24, 2022
A program on solana blockchain to provide escrow services.

Environment Setup Install Rust from https://rustup.rs/ Install Solana from https://docs.solana.com/cli/install-solana-cli-tools#use-solanas-install-to

Dec 24, 2021
This is solana program template.

Environment Setup Install Rust from https://rustup.rs/ Install Solana from https://docs.solana.com/cli/install-solana-cli-tools#use-solanas-install-to

Dec 28, 2021