Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
387 changes: 387 additions & 0 deletions .github/workflows/anchor-v1.yml

Large diffs are not rendered by default.

30 changes: 22 additions & 8 deletions .github/workflows/anchor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Anchor
name: Anchor v2

on:
push:
Expand All @@ -8,6 +8,16 @@ on:
types: [opened, synchronize, reopened]
branches:
- main
# These projects have no committed Cargo.lock (.gitignore ignores **/*/Cargo.lock),
# so their transitive dependencies resolve fresh on every run and can break with
# nobody touching the code. Dependabot does not cover them either: it is configured
# for directory "/", which is the root workspace, and the per-project anchor/ workspaces are
# what `anchor build` actually resolves. A weekly
# build catches that drift on a cadence instead of at whatever unrelated pull request
# happens to touch these files next. The analyze step already treats a scheduled run
# as "build everything".
schedule:
- cron: '0 3 * * 1'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -50,11 +60,15 @@ jobs:
ignore_pattern=$(grep -v '^#' .github/.ghaignore | grep -v '^$' | tr '\n' '|' | sed 's/|$//')
echo "Ignore pattern: $ignore_pattern"

# Single source of truth for "what is a framework project": a directory
# Single source of truth for "what is an Anchor v2 project": a directory
# whose name is exactly "anchor". `find -type d -name anchor` gives us
# that by construction — no substring matching, no path-segment trickery,
# so siblings like "anchor-example/" or nested files such as
# "anchor-example/app/pages/api/foo.ts" can never enter the build list.
# It is also what keeps the two Anchor workflows disjoint: the Anchor v1
# projects live in "anchor-v1" directories, built by
# .github/workflows/anchor-v1.yml, and an exact-name match on "anchor"
# never sees them.
function get_projects() {
# An empty .ghaignore makes ignore_pattern empty, and `grep -vE ""`
# matches everything, silently emptying the project list - only
Expand Down Expand Up @@ -173,11 +187,11 @@ jobs:
# runs `anchor --version | awk '{print $2}'` and writes the result straight to
# $GITHUB_OUTPUT. `anchor --version` now prints more than one line, so the value
# becomes multi-line and the step dies with "Invalid format", aborting the whole
# job before any project is built. These steps install the same toolchain (Solana
# via the Anza installer, Anchor via avm) and read the version from the first line
# only. The other workflows that use setup-anchor (native, quasar, pinocchio,
# solana-asm) hit the same latent bug once their matrices run; migrate them the
# same way once this is confirmed green.
# job before any project is built. These steps install the toolchain directly
# (Solana via the Anza installer, the Anchor CLI from crates.io) and read the
# version from the first line only. The other workflows that use setup-anchor
# (native, quasar, pinocchio, solana-asm) hit the same latent bug once their
# matrices run; migrate them the same way once this is confirmed green.
- uses: actions/setup-node@v4
with:
node-version: lts/*
Expand Down Expand Up @@ -376,7 +390,7 @@ jobs:
- uses: actions/checkout@v5
- name: Create job summary
run: |
echo "## Anchor Workflow Summary" >> $GITHUB_STEP_SUMMARY
echo "## Anchor v2 Workflow Summary" >> $GITHUB_STEP_SUMMARY
echo "- Total projects: ${{ needs.changes.outputs.total_projects }}" >> $GITHUB_STEP_SUMMARY

# List all processed projects
Expand Down
53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,59 @@ All notable changes to this repository are documented here.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [2026-08-21] - Anchor v1 kept alongside Anchor v2

Anchor v1 is expected to stay on long-term support, and many deployed programs
will stay with it. Both versions of every Anchor example now ship, each built and
tested by its own CI job.

### Added

- Every one of the 55 Anchor examples gains a sibling `anchor-v1/` directory
holding the example exactly as it stood before the v2 port, restored from
`94abbea`, the last commit on `main` before that merge. 864 files. The 17
third-party `.so` test fixtures are byte-identical to the ones already tracked
under `anchor/`, so git stores one copy and the tree grows by ~2.3 MB of text.
- `.github/workflows/anchor-v1.yml` builds and tests them on Anchor 1.1.2,
installed through avm. It is the workflow as it stood at `94abbea`, with
project discovery changed to `find -type d -name "anchor-v1"`. The v2-only IDL
workaround (`anchor#4947`, enum variants) is not carried over: that bug does not
exist in 1.1.2, so v1 builds generate IDLs normally.

### Changed

- The `Anchor` workflow is now `Anchor v2`, so the two checks read as a pair. Its
filename, triggers and `find -type d -name "anchor"` discovery are unchanged.
Both workflows match a directory name exactly, so neither can ever see the
other's projects.
- Both Anchor workflows install the CLI from crates.io (`cargo install anchor-cli
--version <v> --locked`). The v1 job started out installing avm from the tip of
anchor's `main` branch, which meant what CI installed drifted with whatever landed
there; 1.1.2 is an ordinary published release, so it comes from the registry like
2.0.0-rc.1 does.
- Both Anchor workflows now run weekly (v2 Mondays 03:00 UTC, v1 05:00 UTC). The
analyze step has always treated a scheduled run as "build everything", but nothing
declared a schedule, so that path had never executed. It is worth having because no
Anchor project commits a `Cargo.lock` and Dependabot only covers the root workspace,
so dependency drift in either tree is otherwise invisible until an unrelated pull
request happens to touch it.
- The two workflows no longer report colliding check names. Both declared jobs called
`changes`, `summary` and `build-and-test-group-N`; the v1 job names are now
`changes (Anchor v1)`, `anchor-v1-group-N` and `summary (Anchor v1)`.
- Every Anchor example README now names the CLI its commands need, on both sides:
`anchor/` pages say Anchor v2 and `anchor-v1/` pages say Anchor v1. A bare
`anchor build` was unambiguous while the repository had one Anchor and is not
any more. `README.md` and `CONTRIBUTING.md`, which sit above both, show both.

### Note

- The `anchor-v1/` crates are not members of the root Cargo workspace and cannot
be: they carry the same package names as their `anchor/` siblings. `cargo fmt`
and `cargo clippy` therefore do not see them, and the Anchor v1 workflow is what
keeps them honest. They also have no committed `Cargo.lock` (`.gitignore` ignores
`**/*/Cargo.lock`), so their transitive dependencies resolve fresh on each run and
can break without anyone touching the directory.

## [2026-08-16] - Every Anchor example on Anchor v2.0.0-rc.1

All 55 Anchor examples build and pass their tests on 2.0.0-rc.1 (304 tests),
Expand Down
8 changes: 6 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ See [CHANGELOG.md](./CHANGELOG.md) for release history. This file had no changel
## Project structure

- Each example lives at `category/example-name/<framework>/`, e.g. `basics/counter/anchor/`.
- Supported frameworks: `anchor`, `quasar`, `pinocchio`, `native`, `asm`. Use the existing layout as a reference.
- Supported frameworks: `anchor`, `anchor-v1`, `quasar`, `pinocchio`, `native`, `asm`. Use the existing layout as a reference.
- `anchor/` is Anchor v2 (2.0.0-rc.1) and is where new Anchor work goes. `anchor-v1/` is the
same example on Anchor v1 (1.1.2), kept for the v1 LTS line: it is a frozen snapshot and
changes only to keep the v1 build green, not to gain new features.
- Anchor and Quasar programs usually keep Rust tests under `programs/<name>/tests/`.
- Native and Pinocchio tests are Rust + LiteSVM, kept under `program/tests/`.

Expand All @@ -25,7 +28,8 @@ See [CHANGELOG.md](./CHANGELOG.md) for release history. This file had no changel

Run an example's tests with the command for its framework, from the framework directory (e.g. `basics/counter/anchor/`):

- **Anchor:** `anchor test` (runs `cargo test`, per the `[scripts]` table in `Anchor.toml`).
- **Anchor v2** (in `anchor/`): `anchor test` (runs `cargo test`, per the `[scripts]` table in `Anchor.toml`), with the v2 CLI: `cargo install anchor-cli --version 2.0.0-rc.1 --locked`.
- **Anchor v1** (in `anchor-v1/`): the same `anchor test`, with the v1 CLI: `avm install 1.1.2 && avm use 1.1.2`. Selecting the wrong CLI is the usual cause of a confusing build failure in these directories.
- **Quasar:** `quasar test`.
- **Native / Pinocchio:** `cargo test --manifest-path=./program/Cargo.toml` (build first with `cargo build-sbf --manifest-path=./program/Cargo.toml`).

Expand Down
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
# `anchor/Cargo.toml` workspace. `anchor build` uses the project workspace; this
# one is what the repository-wide `cargo fmt` and `cargo clippy` jobs see, and
# they only ever look at members. A crate missing here is a crate CI never lints.
#
# The `anchor-v1/` crates are deliberately absent, and must stay absent. Each is a
# copy of its `anchor/` sibling carrying the same `[package] name`, and one
# workspace cannot hold two packages called the same thing - adding them fails with
# "two packages named `favorites` in this workspace". They do not need an `exclude`
# entry either: nothing here depends on them by path, and each `anchor-v1/Cargo.toml`
# declares its own `[workspace]`, so `anchor build` inside one resolves there. The
# cost is that `cargo fmt` and `cargo clippy` never see them; the Anchor v1 workflow
# compiles and tests them instead.
members = [
#basics
"basics/account-data/native/program",
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

_Solana program examples ('smart contracts') in Anchor, Quasar, Pinocchio, native Rust, and sBPF assembly. Focused on financial software ('DeFi'), plus the basics, tokens, Token Extensions, state compression, and more._

Working, tested, up-to-date examples of common Solana programs (what other chains call smart contracts), maintained by [Quicknode](https://www.quicknode.com/chains/solana). Current as of August 2026 (see [CHANGELOG.md](./CHANGELOG.md)): every example builds and passes CI on **Anchor 2.0.0-rc.1**, the current multi-file program layout (one file per instruction handler, account type, etc), and [LiteSVM](https://github.com/LiteSVM/litesvm) tests rather than the older `solana-test-validator` / web3.js stack.
Working, tested, up-to-date examples of common Solana programs (what other chains call smart contracts), maintained by [Quicknode](https://www.quicknode.com/chains/solana). Current as of August 2026 (see [CHANGELOG.md](./CHANGELOG.md)): every example builds and passes CI on **Anchor 2.0.0-rc.1**, the current multi-file program layout (one file per instruction handler, account type, etc), and [LiteSVM](https://github.com/LiteSVM/litesvm) tests rather than the older `solana-test-validator` / web3.js stack. Every Anchor example also keeps its last **Anchor 1.1.2** version in a sibling `anchor-v1/` directory, built and tested by its own CI job, for programs staying on the Anchor v1 LTS line.

[![Anchor](../../actions/workflows/anchor.yml/badge.svg)](../../actions/workflows/anchor.yml) [![Quasar](../../actions/workflows/quasar.yml/badge.svg)](../../actions/workflows/quasar.yml) [![Pinocchio](../../actions/workflows/pinocchio.yml/badge.svg)](../../actions/workflows/pinocchio.yml) [![Native](../../actions/workflows/native.yml/badge.svg)](../../actions/workflows/native.yml) [![ASM](../../actions/workflows/solana-asm.yml/badge.svg)](../../actions/workflows/solana-asm.yml)
[![Anchor v2](../../actions/workflows/anchor.yml/badge.svg)](../../actions/workflows/anchor.yml) [![Anchor v1](../../actions/workflows/anchor-v1.yml/badge.svg)](../../actions/workflows/anchor-v1.yml) [![Quasar](../../actions/workflows/quasar.yml/badge.svg)](../../actions/workflows/quasar.yml) [![Pinocchio](../../actions/workflows/pinocchio.yml/badge.svg)](../../actions/workflows/pinocchio.yml) [![Native](../../actions/workflows/native.yml/badge.svg)](../../actions/workflows/native.yml) [![ASM](../../actions/workflows/solana-asm.yml/badge.svg)](../../actions/workflows/solana-asm.yml)

Each example is available in one or more of the following frameworks:

- [⚓ Anchor](https://www.anchor-lang.com/) - the most popular framework for Solana development. Build with `anchor build`, test with `anchor test`.
- [⚓ Anchor v2](https://www.anchor-lang.com/) - the most popular framework for Solana development, in its current major version. Lives in `anchor/`. Install with `cargo install anchor-cli --version 2.0.0-rc.1 --locked`, build with `anchor build`, test with `anchor test`.
- [⚓ Anchor v1](https://www.anchor-lang.com/) - the previous major version, on long-term support and still what many deployed programs use. Lives in `anchor-v1/`, alongside the v2 copy of the same example. Install with `avm install 1.1.2 && avm use 1.1.2`, then the same `anchor build` / `anchor test`.
- [💫 Quasar](https://quasar-lang.com/docs) - a newer, more performant framework with Anchor-compatible ergonomics. Build with `quasar build`, test with `quasar test`.
- [🤥 Pinocchio](https://github.com/anza-xyz/pinocchio) - a zero-copy, zero-allocation library for Solana programs. Build with `cargo build-sbf --manifest-path=./program/Cargo.toml`, test with `cargo test --manifest-path=./program/Cargo.toml`.
- [🦀 Native Rust](https://docs.anza.xyz/) - vanilla Rust using Solana's native crates. Build with `cargo build-sbf --manifest-path=./program/Cargo.toml`, test with `cargo test --manifest-path=./program/Cargo.toml`.
Expand Down
18 changes: 18 additions & 0 deletions basics/account-data/anchor-v1/Anchor.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[toolchain]
# Match the repo package manager (pnpm-lock.yaml at root); avoids Anchor's yarn default.
package_manager = "pnpm"
solana_version = "3.1.8"

[features]
seeds = false
skip-lint = false

[programs.localnet]
account_data_anchor_program = "GpVcgWdgVErgLqsn8VYUch6EqDerMgNqoLSmGyKrd6MR"

[provider]
cluster = "Localnet"
wallet = "~/.config/solana/id.json"

[scripts]
test = "cargo test"
5 changes: 5 additions & 0 deletions basics/account-data/anchor-v1/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## 2026-07-07

Added this changelog. Changes prior to this date were tracked in git history only.
14 changes: 14 additions & 0 deletions basics/account-data/anchor-v1/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[workspace]
members = [
"programs/*"
]
resolver = "2"

[profile.release]
overflow-checks = true
lto = "fat"
codegen-units = 1
[profile.release.build-override]
opt-level = 3
incremental = false
codegen-units = 1
40 changes: 40 additions & 0 deletions basics/account-data/anchor-v1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Account Data (Anchor)

> [!NOTE]
> This is the **Anchor v1** copy of this example, kept for programs staying on the
> Anchor v1 LTS line. Every `anchor` command on this page needs the v1 CLI:
> `avm install 1.1.2 && avm use 1.1.2`. The Anchor v2 version of this example is in
> [`../anchor`](../anchor/).

Store and retrieve arbitrary data in a Solana [account](https://solana.com/docs/terminology#account) owned by this [program](https://solana.com/docs/terminology#program).

See also: the [repository catalog](../../../README.md).

## Major concepts

- Account ownership and lamport rent
- Serializing and deserializing account data

## Setup

From this directory (`basics/account-data/anchor/`):

```bash
anchor build
```

Prerequisites: [Agave](https://docs.anza.xyz/) CLI (version in `Anchor.toml` `[toolchain]`), [Anchor](https://www.anchor-lang.com/docs).

## Testing

Tests run in-process with [LiteSVM](https://www.anchor-lang.com/docs/testing/litesvm). No local validator.

```bash
anchor test
```

This runs `cargo test` as configured in `Anchor.toml`. Tests call instruction handlers and check onchain state.

## Usage

Read the program `programs/` source and `Anchor.toml` for deployed program IDs. For deployment, use `anchor build && anchor deploy` against your target cluster.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "account-data-anchor-program"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "account_data_anchor_program"

[features]
default = []
cpi = ["no-entrypoint"]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
idl-build = ["anchor-lang/idl-build"]
anchor-debug = []
custom-heap = []
custom-panic = []

[dependencies]
anchor-lang = "1.1.2"

[dev-dependencies]
litesvm = "0.13.1"
solana-signer = "3.0.0"
solana-keypair = "3.0.1"
borsh = "1.6.1"
solana-kite = "0.4.0"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] }
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::state::AddressInfo;
use anchor_lang::prelude::*;

#[derive(Accounts)]
pub struct CreateAddressInfoAccountConstraints<'info> {
#[account(mut)]
payer: Signer<'info>,

#[account(
init,
payer = payer,
space = AddressInfo::DISCRIMINATOR.len() + AddressInfo::INIT_SPACE,
)]
address_info: Account<'info, AddressInfo>,
system_program: Program<'info, System>,
}

pub fn handle_create_address_info(
context: Context<CreateAddressInfoAccountConstraints>,
name: String,
house_number: u8,
street: String,
city: String,
) -> Result<()> {
*context.accounts.address_info = AddressInfo {
name,
house_number,
street,
city,
};
Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod create;
pub use create::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use anchor_lang::prelude::*;
use instructions::*;

pub mod instructions;
pub mod state;

declare_id!("GpVcgWdgVErgLqsn8VYUch6EqDerMgNqoLSmGyKrd6MR");

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

pub fn create_address_info(
context: Context<CreateAddressInfoAccountConstraints>,
name: String,
house_number: u8,
street: String,
city: String,
) -> Result<()> {
create::handle_create_address_info(context, name, house_number, street, city)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use anchor_lang::prelude::*;

#[account]
#[derive(InitSpace)] // automatically calculate the space required for the struct
pub struct AddressInfo {
#[max_len(50)] // set a max length for the string
pub name: String, // 4 bytes + 50 bytes
pub house_number: u8, // 1 byte
#[max_len(50)]
pub street: String, // 4 bytes + 50 bytes
#[max_len(50)]
pub city: String, // 4 bytes + 50 bytes
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod address_info;

pub use address_info::*;
Loading
Loading