Release notes
Anchor release notes.
1.0.2
1.0.1
1.0.0
0.32.1
0.32.0
0.31.1
0.31.0
0.30.1
0.30.0
0.29.0
1.0.2
Anchor release notes for 1.0.2.
1.0.2 is a patch release with fixes across anchor-cli, anchor-lang, and anchor-client. The most user-visible change is the localnet bind default that unblocks anchor test against solana-test-validator 3.1.10 (see bind localnet to 127.0.0.1 by default).
How to upgrade#
To install the new anchor-cli via AVM:
avm install 1.0.2Or directly from the repository:
cargo install --git https://github.com/otter-sec/anchor --tag v1.0.2 anchor-cli --lockedThen update Anchor crate(s) and TS package(s) to 1.0.2.
Recommended Solana version#
The recommended Solana version is 3.1.10, the same as v1.0.0’s recommended Solana version.
CLI#
Bind localnet to 127.0.0.1 by default#
anchor test now defaults the localnet bind address to 127.0.0.1 rather than 0.0.0.0. The previous 0.0.0.0 default caused solana-test-validator 3.1.10 to panic on startup, which broke the localnet test loop on the recommended Solana toolchain. The bind_address field in Anchor.toml still overrides the default for workspaces that need a different value.
Fall back to a priority fee of 0 on localnet#
anchor deploy and related commands no longer surface a fee-lookup error when targeting a local cluster. The recent-priority-fee RPC method may either fail or return an empty list against localnet, so the CLI now falls back to a priority fee of 0 in both cases and prints a warning. This matches the assumption that localnet does not need fee competition.
Lang#
Faster IDL builds via cached CrateContext#
The IDL build pipeline now caches the parsed crate context inside a OnceLock shared across gen_idl_type invocations within a single compilation. Previously, each emitted type re-parsed lib.rs through CrateContext::parse, which made IDL generation scale poorly with the number of account, instruction, and event types in a program. Workspaces with many defined types see materially shorter IDL build times.
Fix compile error with init and a runtime seeds expression#
#[account(init, ..., seeds = <runtime expression>, bump)] now compiles when the seed list is computed at runtime rather than spelled out as a literal array:
#[derive(Accounts)]pub struct Open<'info> { #[account( init, payer = user, space = 8, seeds = pda_seeds(user.key()), bump, )] pub pda: Account<'info, Dummy>, #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>,}Previously, the generated code pushed a borrowed temporary array (&[__bump][..]) into the runtime signer-seeds vector. The borrow checker rejected this when the rest of the seed list came from a runtime expression because the temporary did not outlive the enclosing block. The fix binds the bump byte to a named local so the borrow lives long enough.
Client#
Replace solana-program with solana-hash#
anchor-client previously depended on solana-program solely to re-export solana_program::hash::Hash. The dependency is now solana-hash, which trims the client’s transitive surface and reduces compile time for downstream Rust SDKs that consume anchor-client.
See the full list of notable changes in the CHANGELOG.
1.0.1
Anchor release notes for 1.0.1.
1.0.1 is a patch release that fixes a regression in AnchorSerialize and AnchorDeserialize when user-supplied #[borsh(...)] attributes are present (see user-provided borsh attributes fix).
How to upgrade#
To bump only the affected crate in an existing 1.0.0 workspace:
cargo update anchor-derive-serdeOtherwise, install the new anchor-cli via AVM:
avm install 1.0.1Or directly from the repository:
cargo install --git https://github.com/otter-sec/anchor --tag v1.0.1 anchor-cli --lockedThen update Anchor crate(s) and TS package(s) to 1.0.1.
Recommended Solana version#
The recommended Solana version is 3.1.10, the same as v1.0.0’s recommended Solana version.
Lang#
Fix user-provided borsh attributes in derives#
Structs and enums carrying custom #[borsh(...)] attributes (for example, #[borsh(skip)] or #[borsh(use_discriminant = true)]) now compile correctly under #[derive(AnchorSerialize, AnchorDeserialize)]:
#[derive(AnchorSerialize, AnchorDeserialize)]#[borsh(use_discriminant = true)]pub enum MyEnum { A = 0, B = 5,}Previously, the derive macros emitted their own item-level #[borsh] attribute alongside any user-supplied one. Only a single item-level #[borsh] attribute is permitted, so the duplicate produced a compile error. The macros now extract user-provided attributes and merge them with the generated ones.
The #[borsh] attribute is not supported when the lazy-account feature is enabled. The only accepted form under lazy-account is #[borsh(use_discriminant = false)].
See the full list of notable changes in the CHANGELOG.
1.0.0
Anchor release notes for 1.0.0.
1.0.0 is the first stable major release of Anchor. It ships a large number of breaking changes designed to clean up long-standing technical debt, modernize the toolchain, and establish a stable foundation going forward. These notes cover the most significant changes. The full list lives in the CHANGELOG.md.
How to upgrade#
Using AVM (recommended)#
-
Update
avmitself before installing the new CLI. Existingavminstalls that already supportself-updatecan update in place:Terminal window avm self-updateOlder installs need a fresh
cargo installfirst to pick up the new binary:Terminal window cargo install avm --git https://github.com/otter-sec/anchor --locked -
Update
anchor-cli:Terminal window avm install 1.0.0
Without AVM#
Install anchor-cli directly:
cargo install --git https://github.com/otter-sec/anchor --tag v1.0.0 anchor-cli --lockedCommon steps#
-
Update Anchor crate(s) to
1.0.0. -
Update TS package(s). The package has been renamed in this release. See TypeScript package rename for the new import path.
Recommended Solana version#
The recommended Solana version is 3.1.10. Install the new tooling with:
sh -c "$(curl -sSfL https://release.anza.xyz/v3.1.10/install)"Breaking changes#
TypeScript package rename#
The TypeScript package has been moved from @coral-xyz/anchor to @anchor-lang/core:
npm install @anchor-lang/coreEvery import in the project needs the new package name:
import * as anchor from '@coral-xyz/anchor'import { Program } from '@coral-xyz/anchor'import * as anchor from '@anchor-lang/core'import { Program } from '@anchor-lang/core'IDL types that were previously imported from @coral-xyz/anchor/dist/cjs/idl are now exported directly from @anchor-lang/core:
import { Idl } from '@coral-xyz/anchor/dist/cjs/idl'import { Idl } from '@anchor-lang/core'Solana 3.0#
Anchor 1.0.0 targets Solana 3.x. Workspaces still on Solana 2.x must upgrade their toolchain before installing the new CLI.
Solana CLI dependency removed#
The anchor CLI no longer depends on the external solana CLI binary. Native implementations are now provided for the most common subcommands, including balance, airdrop, address, and deploy. The solana binary no longer needs to be on PATH for any anchor command to function.
anchor test and anchor localnet use Surfpool by default#
Surfpool replaces solana-test-validator as the default local backend for anchor test and anchor localnet. Pass --validator legacy to keep using solana-test-validator.
Surfpool must be installed for the default anchor test and anchor localnet flow. Verify the installation with surfpool --version. The minimum recommended Surfpool version for use with Anchor is v1.1.2. For installation, follow the Surfpool installation instructions.
Duplicate mutable accounts disallowed by default#
Passing the same mutable account twice in an instruction now produces a runtime error by default. The dup constraint opts back into duplicate mutable accounts when they are intentional:
#[derive(Accounts)]pub struct MyIx<'info> { #[account(mut)] pub account_a: Account<'info, MyData>, #[account(mut, dup)] pub account_b: Account<'info, MyData>,}Legacy IDL instructions replaced by Program Metadata#
The on-chain IDL management instructions that Anchor has used since the beginning have been removed and replaced with the new Program Metadata Program (PMP). IDL uploads through anchor deploy and anchor idl commands work as before. Only the underlying storage mechanism has changed.
The program-id argument of anchor idl init and anchor idl upgrade is now optional. When omitted, the program ID is read from the address field of the IDL file itself.
Existing deployed programs with IDLs require migration. The legacy IDL accounts must be closed before deploying the v1 program, since the v1 binary no longer carries the IDL management instructions. The closure step itself requires the previous v0.32.1 CLI.
Remove program account info from CPI context#
The program field in CpiContext previously held a redundant copy of the program’s AccountInfo. The constructor now takes the program ID directly:
CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts)CpiContext::new(Token::id(), cpi_accounts)interface-instructions feature removed#
The interface-instructions feature flag and the #[interface] attribute have been removed. Use #[instruction(discriminator = <EXPR>)] to specify custom discriminators.
Anchor.toml cleanup#
- The
[registry]section is no longer recognized. Remove it fromAnchor.toml. - The program
archbuild options have been removed from the CLI.
#[error_code] may only appear once per program#
Having more than one #[error_code] block in a single program is now a compile-time error.
Client tx signing error no longer panics#
RequestBuilder::send() (and its variants) previously panicked when signing failed. It now returns an Err instead.
AVM#
avm self-update#
A v1-capable avm can update itself without going back through cargo install:
avm self-updateBootstrapping to a version that supports the command requires a one-off cargo install first:
cargo install avm --git https://github.com/otter-sec/anchor --tag v1.0.0 --lockedavm also passively warns when it detects that a newer version of itself is available.
Pre-release support#
All three avm commands (install, list, update) now recognize pre-release version labels:
avm install latest-pre-releaseavm list --pre-releaseavm update --pre-releaseCLI#
Lifecycle hooks#
Shell commands can now run at key points in the build, test, and deploy lifecycle through a [hooks] section in Anchor.toml:
[hooks]pre_build = "echo building..."post_build = ["echo done", "echo done again"]pre_test = "some-setup-script"post_deploy = "some-notify-script"Supported hooks: pre_build, post_build, pre_test, post_test, pre_deploy, post_deploy.
LiteSVM test template is now the default#
anchor init now generates a LiteSVM test template by default, replacing the previous TypeScript-based default. A different template can be selected explicitly:
anchor init my-program --test-template molluskanchor init my-program --test-template mochaProgram ID mismatch check#
anchor build now checks that the program ID declared in source matches the public key in the program’s keypair file and emits an error when they differ. The check is skipped during anchor test where ephemeral keypairs are common. Pass --ignore-keys to suppress the check on builds.
--install-agent-skills#
Pass --install-agent-skills to anchor init to install Solana agent-AI skills into the new workspace automatically.
anchor login removed#
anchor login has been removed alongside the [registry] section of Anchor.toml.
Lang#
Migration<'info, From, To> account type#
The new Migration type migrates an account between two different data layouts in a single instruction:
#[derive(Accounts)]pub struct MigrateMyAccount<'info> { #[account(mut)] pub my_account: Migration<'info, OldAccount, NewAccount>,}The account is deserialized as From and serialized back as To on instruction exit.
declare_program!() improvements#
Several renames apply to the code generated by declare_program!(). The utils module is now parsers, and the deserialization methods are now named parse instead of try_from_bytes:
my_program::utils::Account::try_from_bytes(&data)?;my_program::parsers::Account::parse(&data)?;
my_program::utils::Event::try_from_bytes(&data)?;my_program::parsers::Event::parse(&data)?;The errors module is now error (singular), and ProgramError has been renamed to <ProgramName>Error, where <ProgramName> is the PascalCase name of the declared program:
my_program::errors::ProgramErrormy_program::error::MyProgramErrorA typed instruction parser is now generated alongside the CPI helpers. Call my_program::parsers::Instruction::parse() with a solana_instruction::Instruction to decode any instruction belonging to the program.
Composite (non-instruction) account structs used more than once in a program previously caused duplicate definitions or incorrect instruction-name derivation in the generated code. Each composite account definition is now guaranteed to be unique, and colliding instruction names have a numeric suffix appended until uniqueness is reached.
Error generation has also been improved. declare_program!() previously interfered with the IDL error module of the declaring program. Programs that use declare_program!() alongside their own #[error_code] block now produce correct error code definitions.
Use declare_program!() with only anchor-client#
declare_program!() no longer requires anchor-lang in client-side contexts. Adding anchor-client as a dependency is sufficient.
Remove lifetime definitions from Context#
Three redundant lifetime parameters have been removed from Context. Most programs are unaffected. Programs that referenced the removed lifetimes explicitly need to update their annotations:
// Before (v0.32)pub fn my_handler<'a, 'b, 'c, 'info>( ctx: Context<'a, 'b, 'c, 'info, MyAccounts<'info>>,) -> Result<()> { ... }
// After (v1)pub fn my_handler<'info>(ctx: Context<'info, MyAccounts<'info>>) -> Result<()> { ... }// or simply (when the lifetime is inferred)pub fn my_handler(ctx: Context<MyAccounts>) -> Result<()> { ... }Deprecate AccountInfo in Accounts macro#
Using AccountInfo directly inside a #[derive(Accounts)] struct now emits a compile-time warning. Prefer UncheckedAccount or a more specific account type.
Relaxed PDA seed syntax#
Seed expressions inside seeds = [...] constraints accept a broader set of Rust expressions. More complex seed expressions reduce the likelihood that the seeds can be represented in the IDL and resolved automatically by the client.
Owner check on account reload#
Account::reload() now re-validates the account’s owner, matching the behavior of the initial load.
Generic Program type#
Program<'info> can now be used without a generic type argument for executable-only validation when the concrete program type isn’t known statically:
pub program: Program<'info>,Owners exported from prelude#
anchor_lang::Owners is now re-exported from anchor_lang::prelude, removing the need for a separate use statement.
Borsh upgraded to 1.5.7#
Both the Rust and TypeScript Borsh implementations have been updated to 1.5.7. The borsh dependency in Cargo.toml must be compatible with that version.
#[instruction(..)] argument validation#
The compiler now enforces that the types and count of arguments declared in #[instruction(..)] match the corresponding instruction handler’s signature, catching mismatches that were previously silent.
IDL#
Unsupported field types produce a hard error#
Defined types that contained unsupported fields (such as tuple types) were previously omitted from the generated IDL silently. They now produce a compile-time error:
error: Unsupported type --> programs/name/src/lib.rs:37:8 |37 | x: (u32, u32), | ^^^^^^^^^^Programs that previously relied on silent omission must refactor those fields into supported types before building.
Full path account names supported in IDL generation#
The IDL builder previously rejected account types that shared a short name with another type in a different module (for example, program::module::Account conflicting with other::Account). The duplicate-name check has been removed, so fully qualified account paths now resolve without error.
address constraint resolves constants with numbers in their names#
The address constraint previously failed to resolve constants whose identifiers contained numbers, such as MY_PROGRAM_V2_ID. The resolver now handles them correctly.
serde_json is now optional#
The serde_json dependency of anchor-lang-idl is now behind an opt-in feature flag. Disabling it reduces compile time when JSON serialization isn’t needed.
External accounts excluded from IDL#
Accounts defined in external programs (such as SPL token accounts referenced through CPI) are no longer included in the generated IDL’s accounts array, keeping the IDL scoped to the declaring program’s own types.
Custom error offset respected#
The offset = N argument in #[error_code] is now reflected in the generated IDL, so IDL error codes match the values emitted at runtime.
TypeScript#
IDL fetching uses Program Metadata Program#
The TypeScript client now fetches IDLs from the new Program Metadata Program storage. Existing code calling Program.fetchIdl() continues to work without changes.
Rust client#
FnMut closures for event subscriptions#
program.on::<Event>(|event, slot| { ... }) now accepts FnMut closures, so the callback can capture and mutate state from the surrounding scope.
Reduced re-exports from anchor-client#
anchor-client previously re-exported the entirety of solana-sdk, which made types easy to discover but pulled in a large transitive dependency. It now only re-exports the types that are part of its own public API. Programs that depended on transitive solana-sdk types through anchor-client must now add the underlying crates (solana-account, solana-pubkey, and so on) as direct dependencies.
See the full list of notable changes in the CHANGELOG.
0.32.1
Anchor release notes for 0.32.1.
0.32.1 patches a handful of 0.32.0 regressions, most notably a race condition during program deployment. The full list of changes lives in the CHANGELOG.md.
How to upgrade#
-
Update
anchor-cli:Terminal window avm install 0.32.1 -
Update Anchor crate(s) to
0.32.1. -
Update TS package(s) to
0.32.1.
Recommended Solana version#
The recommended Solana version is 2.3.0. Install it with:
sh -c "$(curl -sSfL https://release.anza.xyz/v2.3.0/install)"CLI#
anchor deploy race condition#
0.32.0 shipped automatic IDL upload on every deploy, but the IDL upload could race the program upload and run before the program account was fully available. anchor deploy now waits for the program to be fully available before uploading the IDL.
Lang#
realloc deprecation warning removed#
A leftover deprecation warning for realloc was emitted on builds in 0.32.0. The warning is removed in this release.
See the full list of notable changes in the CHANGELOG.
0.32.0
Anchor release notes for 0.32.0.
0.32.0 is the last planned release before the breaking changes that stabilize Anchor 1.0. These notes cover the most significant changes; the full list lives in the CHANGELOG.md.
How to upgrade#
-
Update
anchor-cli:Terminal window avm install 0.32.0 -
Update Anchor crate(s) to
0.32.0. -
Update TS package(s) to
0.32.0.
Recommended Solana version#
The recommended Solana version is 2.3.0. Install the new tooling with:
sh -c "$(curl -sSfL https://release.anza.xyz/v2.3.0/install)"CLI#
anchor verify switches to solana-verify#
Anchor versions before 0.32.0 produced verifiable builds using the solanafoundation/anchor Docker image. 0.32.0 replaces that pipeline with solana-verify under the hood. The user-facing entry point is unchanged: anchor verify still produces and verifies builds. Verifying a build produced by Anchor < 0.32.0 with the new CLI is expected to fail because the verification mechanism has changed.
IDL upload by default on deploy#
anchor deploy now uploads the IDL on every deployment by default. Pass --no-idl to deploy the program without touching the on-chain IDL.
Minimum Rust version raised to 1.89.0#
IDL builds now require Rust 1.89.0 or higher because earlier Rust versions don’t expose the stabilized Span::local_file(). Update the toolchain with:
rustup updateConfirm the installed version with:
rustc --versionThis is the host Rust toolchain, distinct from the forked rustc that the Solana platform tools use to compile programs.
IDL#
IDL building is now stabilized#
With Span::local_file() stabilized, IDLs build against the current stable Rust compiler instead of nightly. That removes a class of upstream-nightly breakages that previously surfaced as build errors on 0.31.0 and earlier:
no method named source_file found for struct proc_macro2::Span in the currentscopeLang#
Better error message for init on SystemAccount#
init-ing a SystemAccount previously surfaced as a confusing missing-crate error:
error[E0425]: cannot find crate `try_from_unchecked` in the list of imported crateserror[E0425]: cannot find crate `try_from` in the list of imported cratesThe compile-time error now explains the actual constraint and suggests an alternative:
Cannot use `init` on a `SystemAccount`.The `SystemAccount` type represents an already-existing accountowned by the system program and cannot be initialized.If you need to create a new account, use a more specific account typeor `UncheckedAccount` and perform manual initialization instead.Use solana-invoke instead of solana_cpi::invoke for CPI#
solana_cpi::invoke from solana-program is heavier on compute units than necessary. Replacing it with solana-invoke saves an average of 5% CUs across CPI call sites in Anchor programs.
Solang is no longer supported#
Solang templates are no longer bundled with Anchor. Projects that want to keep using Solang must build with Solang’s standalone tooling.
TypeScript#
Remove event parsing panic issues#
A maliciously crafted event could previously panic the TS event parser. The parser’s regex has been hardened to fail closed instead of panicking.
Added support for bun as a package manager#
bun joins npm, yarn, and pnpm as a recognized value for toolchain.package_manager in Anchor.toml:
[toolchain]package_manager = "bun"The same value is accepted when scaffolding a new workspace:
anchor init <NAME> --package-manager bunThe default remains yarn.
See the full list of notable changes in the CHANGELOG.
0.31.1
Anchor release notes for 0.31.1.
0.31.1 is a patch release that fixes proc-macro2-related IDL build errors (see proc-macro2 build fix). Future Anchor releases will be published under the solanafoundation GitHub organization.
How to upgrade#
-
Update
anchor-cli:Terminal window avm install 0.31.1 -
Update Anchor crate(s) to
0.31.1. -
Update TS package(s) to
0.31.1.
Recommended Solana version#
The recommended Solana version is 2.1.0, the same as v0.31.0’s Recommended Solana Version.
Docker#
Docker images have moved to solanafoundation/anchor on Docker Hub. All future images will be published under that namespace.
IDL#
proc-macro2 build fix#
proc-macro2 1.0.95 removed the source_file() method on Span to track an upstream nightly change (rust-lang/rust#139671). The removal surfaced as a build error in earlier Anchor versions:
error[E0599]: no method named `source_file` found for struct `proc_macro2::Span` in the current scopeThe IDL build now compiles against proc-macro2 >= 1.0.95.
TypeScript#
Account resolver no longer requires wallet#
Signer resolution previously required a wallet field on the Provider implementor, failing with:
This function requires the `Provider` interface implementor to have a `wallet` field.The resolver now only requires Provider.publicKey.
Multiple constant generics#
Multiple constant generics on a type no longer trigger parsing errors.
See the full list of notable changes in the CHANGELOG.
0.31.0
Anchor release notes for 0.31.0.
0.31.0 is the last major release before v1. These notes cover the most significant changes (see CHANGELOG.md for all changes).
How to upgrade#
-
Install the latest version of
avm:Terminal window cargo install --git https://github.com/otter-sec/anchor avm --locked --forceThis is required for the new prebuilt binary install path. See Install from binary.
-
Update
anchor-cli:Terminal window avm install 0.31.0 -
Update Anchor crate(s) to
0.31.0. -
Update TS package(s) to
0.31.0.
Recommended Solana version#
The recommended Solana version is 2.1.0. Several Solana binaries have been renamed under the Agave transition, so this upgrade involves replacing the toolchain entirely. Install the new tooling with:
sh -c "$(curl -sSfL https://release.anza.xyz/v2.1.0/install)"Setting toolchain.solana_version in Anchor.toml handles this automatically. See Automatic Agave transition.
AVM#
Install from binary#
avm install now downloads prebuilt binaries from GitHub by default. Supported targets:
aarch64-apple-darwinx86_64-unknown-linux-gnux86_64-apple-darwinx86_64-pc-windows-msvc
Pass --from-source to the install command to fall back to building from source (required on unsupported platforms).
CLI#
Automatic Agave transition#
As noted in Recommended Solana version, several Solana binaries have been renamed to Agave. solana-install is deprecated as of 1.18.19 and logs a deprecation banner that older Anchor versions fail to parse:
⚠️ solana-install is deprecated and will be discontinued when v1.18 is no longer supported. Please switch to Agave: https://github.com/anza-xyz/agave/wiki/Agave-TransitionWhen solana_version in [toolchain] is greater than 1.18.19, Anchor now installs and switches to agave-install automatically:
[toolchain]solana_version = "2.1.0"solana-program warning#
Adding solana-program as a direct dependency of an Anchor program risks version conflicts between Solana v1 and v2 crates. Builds that include it now print a warning:
WARNING: Adding `solana-program` as a separate dependency might cause conflicts.To solve, remove the `solana-program` dependency and use the exported crate from `anchor-lang`.`use solana_program` becomes `use anchor_lang::solana_program`.Program name: `my-program`Pass cargo args to IDL build#
anchor build and anchor idl build now forward cargo arguments through to the IDL build command, so passing --features through -- builds the program and its IDL with the feature enabled:
anchor build -- --features my-feature--no-idl flag for tests#
When the program changes but its public API doesn’t, regenerating the IDL is wasted work. Mirroring --no-idl on builds, the test command now accepts the same flag:
anchor test --no-idlmollusk test template#
Initialize a workspace with the new mollusk test template:
anchor init my-program --test-template molluskclean#
anchor clean now also removes the generated .anchor directory. The command behaves like cargo clean, but preserves program keypairs.
Automatic IDL conversion#
In v0.30, legacy (pre-v0.30) IDLs had to be converted with anchor idl convert before any other command could use them. Most CLI commands now perform that conversion transparently, so legacy and new IDLs work interchangeably. idl fetch is the one exception and still emits the on-chain bytes verbatim.
Package manager#
Anchor has historically defaulted to yarn, and switching was awkward because several commands hard-required yarn on PATH. That coupling is gone. Specify the package manager in Anchor.toml:
[toolchain]package_manager = "npm"Or pass it when creating a new workspace:
anchor init <NAME> --package-manager npmThe supported values are npm, yarn, and pnpm. The default is yarn.
Shell completions#
Shell completions can now be generated for bash, zsh, fish, and PowerShell. See Shell completions.
Lang#
Stack memory improvements#
Stack usage from init constraints has been reduced significantly, and stack warnings on builds are now reliable when targeting Solana v2 (platform-tools v1.42). The rest of this section explains why. Skip to Custom discriminators if you don’t need the background.
The most common source of stack-violation errors in Anchor programs is the generated try_accounts() function, where instruction deserialization and constraint validation both run. Co-locating that work is convenient for constraints, but it makes it trivial to overshoot the SVM’s fixed 4096-byte stack just by adding accounts. The mangled build log usually looks like:
Error: Function _ZN71_$LT$pr..Test$u20$as$u20$anchor_lang..Accounts$LT$pr..TestBumps$GT$GT$12try_accounts17h5572074d55b9e638E Stack offset of 4112 exceeded max offset of 4096 by 16 bytes, please minimize large stack variables.Three external developments compounded the problem. Rust/LLVM changes in Solana v1.18 increased try_accounts()’s stack footprint, lowering the threshold for hitting violations. The stack-warning logs were unreliable, so going over the limit didn’t always surface at build time. And the “Account data direct mapping” feature, which is on by default in the local validator, meant that exceeding the stack at runtime triggered undefined behavior rather than a clean panic.
Undefined behavior is particularly hard to debug because tests can appear to pass while a different input silently corrupts account bytes. Reported instances include #2955, #3113, and #3196.
The unreliable warnings are fixed in Solana v2’s platform-tools v1.42, so build-time warnings are now trustworthy. The largest contributor to stack pressure was identified as the init constraint, which expanded into a long inline block inside try_accounts() and stacked badly when multiple init accounts were used. The expansion now lives inside an immediately-invoked closure (#2939), giving each invocation its own stack frame. Looking further out, SIMD-0166 proposes dynamic stack frames as a runtime-level fix.
Stack-related problems should be considerably rarer on Anchor v0.31 + Solana v2. Lingering issues are tracked in otter-sec/anchor#3097.
Custom discriminators#
Anchor’s discriminator handling had several long-standing limitations:
- 8 bytes is sometimes too costly given Solana’s 1232-byte transaction size cap
- The
Discriminatortrait had a fixed-size[u8; 8]field, blocking implementations for non-Anchor programs (includingdeclare_program!()) - Discriminators were not customizable
- Renaming the underlying type changed its discriminator, breaking deployed programs
This release adds support for custom discriminators. The default 8-byte derivation is unchanged. The discriminator argument on Anchor attribute macros opts into an explicit value:
#[account(discriminator = 1)]#[event(discriminator = [1, 2])]#[instruction(discriminator = MY_CONST)]
Any constant expression is accepted on the right-hand side, with the custom-discriminator integration test exercising the full surface area.
Discriminators must remain unique within a program. Any length is allowed at the trait level (including zero, since some non-Anchor programs like SPL Token have no account discriminator at all), but IDL generation rejects empty discriminators for safety. Programs without discriminators must not rely on the discriminator for safety checks.
IDL generation also rejects ambiguous discriminators, meaning values where one is a prefix of another. With 1-byte discriminators this gets restrictive quickly. An account with discriminator [1] precludes any other discriminator starting with 1 (such as [1, 2, 3, 4]), so leave headroom when picking short values.
Custom discriminators also unlock first-class non-Anchor program support via declare_program!() on the Rust side and the TypeScript client.
Discriminator trait#
The discriminator() method of the Discriminator trait has been removed. Replace any discriminator() call site with the DISCRIMINATOR associated constant.
The trait itself is now re-exported from anchor_lang::prelude so the common pattern of hardcoding the 8-byte discriminator length can be replaced with the trait’s associated constant:
space = 8 + ...space = MyAccount::DISCRIMINATOR.len() + ...LazyAccount#
LazyAccount<'info, T> is an experimental drop-in replacement for Account<'info, T> aimed at performance-sensitive paths. See its documentation for whether it fits the workload. Using LazyAccount requires enabling the lazy-account feature on anchor-lang.
cfg attribute on instructions#
cfg attributes are now supported on instructions:
#[program]mod my_program { #[cfg(feature = "my-feature")] pub fn my_feature(ctx: Context<MyFeature>) -> Result<()> {}}Unnamed and unit structs with InitSpace#
Unnamed and unit structs gained Anchor support in v0.30, but #[derive(InitSpace)] didn’t work for them. Both shapes are now supported:
#[derive(InitSpace)]pub struct Unnamed(pub u64, #[max_len(64)] pub Vec<u8>);
#[derive(InitSpace)]pub struct Unit;Account parser#
declare_program!() now also generates an account parser:
declare_program!(my_program);This will generate something similar to:
pub enum Account { SomeAccount(SomeAccount), OtherAccount(OtherAccount),}Call my_program::utils::Account::try_from_bytes() to deserialize any account owned by the program into the right variant.
declare_program! improvements#
The following issues related to declare_program! have been fixed:
- Being unable to use constant bytes (#3287)
- Missing docs from the generated constants (#3311)
- Compilation errors related to incorrectly adding
derives andreprs to type aliases (#3504) - Being unable to use
dataas an instruction parameter (#3574)
SPL#
New Token 2022 instructions#
The following Token 2022 instructions were added:
burn_checkedmint_to_checkedapprove_checkedwithdraw_withheld_tokens_from_accounts
IDL#
Safety comment checks#
In v0.30.1, enabling all features in Rust Analyzer would panic because the idl-build feature expected an environment variable that anchor build sets but Rust Analyzer doesn’t:
custom attribute panickedmessage: Safety checks failed: Failed to get program pathThe check is now lenient when the variable is absent.
address constraint with non-const expressions#
A v0.30 regression caused non-const expressions in the address constraint to fail to build:
#[derive(Accounts)]pub struct MyIx { #[account(address = my_account.authority())] pub authority: Signer<'info>, pub my_account: Account<'info, MyAccount>,}Fixed in #3216.
Program accounts with full paths#
Fully-qualified external program types now work in the accounts struct:
#[derive(Accounts)]pub struct FullPath<'info> { pub external_program: Program<'info, external::program::External>,}IdlBuilder#
build_idl() couldn’t gain new parameters without a breaking change. The new builder API solves that:
let idl = IdlBuilder::new().program_path(path).skip_lint(true).build()?;See IdlBuilder for the full API.
Generation improvements#
The following issues with the IDL generation have been fixed:
- A bug where using tuple parameters in instructions would result in an incorrect IDL (#3294)
- A bug where doc comments could trigger false-positives during module paths conversion (#3359)
- A bug where the generated IDL only has partial resolution information (#3474)
- Being unable to use constant identifiers as generic arguments (#3522)
- Being unable to pass in a
Pubkeyconstant toseeds::program(#3559) - Being unable to pass in an account or an argument to
seeds::program(#3570)
TypeScript#
Simpler Program construction#
TypeScript’s structural inference of JSON imports made the Program constructor awkward to call without an extra cast:
import * as idl from './idl/my_program.json'import type { MyProgram } from './types/my_program'
const program = new Program(idl as unknown as MyProgram, provider)The constructor no longer infers the IDL type from its idl argument, so the explicit type parameter is honored without casting:
const program = new Program<MyProgram>(idl, provider)Error improvements#
Account resolution error now includes the accounts that weren’t able to get resolved:
Reached maximum depth for account resolution. Unresolved accounts: `pda`, `anotherPda`Similarly, unsupported view method error now includes the possible causes:
Error: Method does not support views. The instruction should return a value, and its accounts must be read-onlyType improvements#
Tests commonly reached for // @ts-ignore to access the payer keypair:
// @ts-ignoreconst payer = program.provider.wallet.payerThe Provider interface now declares an optional wallet?: Wallet field, and Wallet declares an optional payer?: Keypair field. The non-null assertion (!) replaces the suppression in test code, where these fields are guaranteed:
const payer = program.provider.wallet!.payer!Better confirmation#
Provider.sendAndConfirm() now accepts an optional blockhash for more reliable confirmation:
await program.provider.sendAndConfirm(tx, signers, { blockhash: ... });Programs with numbers in their name#
anchor.workspace now resolves programs whose names contain digits in every casing scenario. See #3450 for the full breakdown.
Rust client#
tokio support#
anchor-client is now compatible with tokio when the async feature is enabled. See the tokio example.
Mock client#
Enabling the mock feature lets tests pass in a mock RPC client:
anchor-client = { version = "0.31.0", features = ["mock"] }See the full list of notable changes in the CHANGELOG.
0.30.1
Anchor release notes for 0.30.1.
0.30.1 is a quality-of-life patch release. There are no major breaking changes from 0.30.0.
How to upgrade#
-
Update
anchor-cli:Terminal window avm install 0.30.1 -
Update Anchor crate(s) to
0.30.1. -
Update TS package(s) to
0.30.1.
Recommended Solana version#
This release supports any Solana version above 1.17.3, with 1.18.17 recommended. Upgrade Solana tools with:
solana-install init 1.18.17IDL#
Convert legacy IDLs#
The IDL crate gained support for converting legacy IDLs (pre-Anchor v0.30) to the new spec. Add the convert feature to enable it programmatically:
anchor-lang-idl = { version = "0.1.1", features = ["convert"] }Then call convert_idl. The same conversion is also exposed as the idl convert CLI command.
Unsupported seed expressions#
Some seed expressions cannot currently be stored in the IDL. A representative case is the math expression &(my_account.data + 1).to_le_bytes():
#[derive(Accounts)]pub struct SeedMathExpr<'info> { #[account(seeds = [&(my_account.data + 1).to_le_bytes()], bump)] pub math_expr_account: UncheckedAccount<'info>, pub my_account: Account<'info, MyAccount>,}
#[account]pub struct MyAccount { data: u64,}A regression in IDL generation had been surfacing such expressions as compile errors. The compile errors are gone, with the side effect that clients cannot automatically resolve these accounts either.
Fields with address constraint#
Field expressions used as an address constraint no longer fail IDL generation:
#[derive(Accounts)]pub struct Initialize<'info> { #[account(address = my_account.authority)] pub authority: UncheckedAccount<'info>, pub my_account: Account<'info, MyAccount>,}
#[account]pub struct MyAccount { authority: u64,}Such accounts still don’t resolve automatically when the constraint expression isn’t constant. The has_one constraint is preferable in those cases:
#[derive(Accounts)]pub struct Initialize<'info> { pub authority: UncheckedAccount<'info>, #[account(has_one = authority)] pub my_account: Account<'info, MyAccount>,}Override nightly version on builds#
IDL generation uses the nightly compiler, which can fail to build on certain nightly versions. The toolchain can now be pinned via the RUSTUP_TOOLCHAIN environment variable.
Recursive generation#
Recursive external type resolution during IDL generation no longer produces a compile error. See PR #2946 for the underlying cause.
New spec crate#
Adding features to the IDL crate (such as the convert feature) previously forced a version bump even when the spec itself was unchanged. The IDL spec now lives in its own crate, whose version is recorded in the idl.metadata.spec field. The new spec crate is also re-exported through anchor_lang_idl::types for convenience.
CLI#
anchor idl convert command#
Convert a legacy IDL JSON file to the new spec:
anchor idl convert <PATH_TO_IDL_JSON>anchor idl type command#
Generate a TypeScript IDL type (with camelCase fields) from an existing IDL JSON file:
anchor idl type <PATH_TO_IDL_JSON>anchor idl build toolchain override#
See the IDL section for context. The CLI honors the same environment variable:
RUSTUP_TOOLCHAIN="nightly-2024-05-09" anchor idl buildAutomatic program id updates#
When building a program for the first time, the program id declarations are updated automatically if Anchor.toml has no [programs.localnet] entry. This is equivalent to running anchor keys sync, but happens only on that first build.
Upgradeable program clones#
A breaking change in Solana 1.17.12 left programs cloned through [[test.validator.clone]] unusable in the test validator. The minimal repro:
[test.validator]url = "https://api.mainnet-beta.solana.com"
[[test.validator.clone]]address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"The fix landed on both the Anchor and Solana sides and requires solana-cli >= 1.18.10.
File system error improvements#
Rust’s default file-not-found error omits the offending path, which makes debugging painful. Filesystem errors raised by Anchor now include the path.
Lang#
Using legacy IDLs with declare_program!#
declare_program!() now accepts legacy (pre-v0.30) IDLs. The macro works as long as the legacy spec can describe the program faithfully. Programs that use non-default features (zero-copy, custom repr, etc.) may produce a declaration that fails to compile or is silently incorrect.
There are two paths around this. The first is to run anchor idl convert and patch the result by hand. The second, preferred path is to upgrade the program to v0.30 and regenerate its IDL, since the new IDL spec was added precisely because the legacy spec couldn’t describe modern programs reliably. If dependency upgrades are blocking, strip them. IDL generation only inspects signatures, so program logic and non-Anchor dependencies can be deleted from the temporary build. The spl-token IDL stub demonstrates the minimal shape required.
declare_program! fixes#
Several inputs that should have worked previously caused declare_program!() to fail compilation:
- Defined types (e.g.
structs) used as instruction parameters - Types with
constgenerics Vec<u8>arguments- Instructions with a non-unit return type
- Optional accounts in client-generated code
- The
bytemuckunsafeaccount serialization mode
Tuple struct fields, which previously inherited Rust’s private default, are now generated as public.
pubkey! macro#
solana-program provides pubkey! for compile-time pubkey literals:
let key = pubkey!("11111111111111111111111111111111");use std::str::FromStr;let key = Pubkey::from_str("11111111111111111111111111111111").unwrap();The macro previously expanded to ::solana_program, so consumers had to include solana-program directly even when using Anchor. pubkey!() is now re-exported from anchor_lang::prelude, and solana_program is itself re-exported from anchor_lang, so the direct solana-program dependency can be dropped from Cargo.toml if it was added solely for this macro.
ID_CONST constant#
declare_id!() and declare_program!() declare ID as static, which prevents compile-time use. Both macros now also emit ID_CONST, the same value declared as const so it can participate in const evaluation.
Stack usage of token extensions#
The token extensions constraints added in 0.30.0 use less stack.
Error propagation from integer conversion errors#
Integer conversion errors now propagate through ?:
let n: i32 = u32::MAX.try_into()?;SPL#
Export ATA crate#
spl-associated-token-account is now re-exported from anchor_spl::associated_token. Drop the direct dependency the same way mpl-token-metadata was dropped in 0.29.0:
[dependencies]anchor-spl = "0.30.1"spl-associated-token-account = "3.0.2"TypeScript#
ATA resolution#
Account resolution now also covers associated token accounts. Instructions that include ATAs now type-error when those accounts are passed to .accounts(). Drop them from the call so the resolver can fill them in.
Defined types in generics#
Defined types (structs, enums, or type aliases) used as generic arguments no longer fail IDL generation:
param: GenericStruct<MyStruct>,Versioned transactions#
AnchorProvider now sets maxSupportedTransactionVersion correctly when sending versioned transactions.
New errors package#
Anchor’s TS error definitions now live in their own package, @coral-xyz/anchor-errors.
See the full list of notable changes in the CHANGELOG.
0.30.0
Anchor release notes for 0.30.0.
These notes cover the main changes in 0.30.0. The complete list of notable changes lives in the CHANGELOG.md.
How to upgrade#
-
Update
avm:Terminal window cargo install --git https://github.com/otter-sec/anchor --tag v0.30.0 avm --locked -
Update
anchor-cli:Terminal window avm install latest -
Update Anchor crate(s) to
0.30.0. Optionally, runcargo updateto update other dependencies to the latest compatible versions. -
Update TS package(s) to
0.30.0.
Recommended Solana version#
This release supports any Solana version above 1.16, with 1.18.8 recommended. Upgrade Solana tools with:
solana-install init 1.18.8IDL#
The IDL type specification and generation have been rewritten. See PR #2824 for the design discussion.
idl-build feature#
idl-build feature is now required in your program’s Cargo.toml definition in order for the IDL generation to work.
Without this feature, anchor build outputs:
anchor buildError: `idl-build` feature is missing. To solve, add
[features]idl-build = ["anchor-lang/idl-build"]
in `<PATH_TO_CARGO_TOML>`.Every crate used to generate type definitions for the IDL must be listed in the idl-build feature, for example anchor-spl/idl-build or some-program/idl-build.
Lang#
Dependency free program declaration#
Depending on multiple crates that pull in different Anchor versions has long been painful. The new declare_program!() macro generates a program client directly from an IDL, removing the runtime version coupling:
declare_program!(program_name);program_name matches a file in the workspace’s idls directory, so the example above expects idls/program_name.json to exist. The generated client supports both on-chain CPI and off-chain RPC usage, sidestepping dependency hell. See the on-chain CPI example and the macro documentation for full details.
Token extensions#
Constraints#
New account constraints cover the Token Extensions (Token 2022) program. Each field is referenced under the extensions prefix and joined with ::, for example extensions::group_pointer::authority = <EXPR>.
Each constraint works with or without the init constraint. The token-extensions integration test shows the full set in use.
CPI wrappers#
anchor-spl now ships CPI wrappers for the Token Extensions program under anchor_spl::token_2022_extensions.
#[interface] attribute#
Transfer hooks can now be wired up with the new #[interface] attribute, which replaces Anchor’s default instruction discriminator with the interface instruction’s discriminator. Two values are currently supported: spl_transfer_hook_interface::initialize_extra_account_meta_list and spl_transfer_hook_interface::execute:
mod my_hook_program { #[interface(spl_transfer_hook_interface::initialize_extra_account_meta_list)] pub fn initialize(ctx: Context<Initialize>, metas: Vec<AnchorExtraAccountMeta>) -> Result<()> { /* ... */ }
#[interface(spl_transfer_hook_interface::execute)] pub fn execute(ctx: Context<Execute>, amount: u64) -> Result<()> { /* ... */ }}Optional bumps#
Bumps for unspecified optional accounts no longer default to u8::MAX. The optional bump type is now Option<u8>, and missing entries are None.
Less heap allocations#
Borsh’s try_to_vec, which Anchor uses for events, CPI, and return data, allocates 1024 bytes per call regardless of payload size. The default has been lowered to 256 bytes. The new InstructionData::write_to() method also writes into an existing allocation, avoiding the fresh allocation InstructionData::data() creates.
CLI#
Priority fees in CLI#
Landing transactions on mainnet-beta increasingly requires priority fees. IDL commands now accept a --priority-fee argument:
anchor idl erase-authority --program-id <PROGRAM_ID> --priority-fee 9000Without an explicit value, the median fee of the last 150 confirmed slots is used.
--no-idl flag on builds#
IDL generation requires a full program build. When the program’s public API hasn’t changed, the --no-idl flag skips IDL regeneration:
anchor build --no-idlIDL buffer is closed after idl upgrade#
After an IDL upgrade, the buffer account is closed and its lamports returned to the IDL authority.
Pass deploy arguments to solana-cli#
Arguments after -- are forwarded from anchor deploy to solana program deploy:
anchor deploy -- --finalVerifiable deployments#
Like verifiable builds, deployments can now use the verifiable build artifact instead of the default build:
anchor deploy --verifiableAccept package name as program name#
The --program-name (-p) argument now accepts a program’s package name in addition to its snake_case lib name:
anchor build -p my-programDeactivate test-validator features#
Test-validator features can now be deactivated from Anchor.toml:
[test.validator]deactivate_feature = ["GDH5TVdbTPUpRnXaRyQqiKUa7uZAbZ28Q2N9bhbKoMLm", "zkiTNuzBKxrCLMKehzuQeKZyLtX2yvFcEKMML8nExU8"]Crate and package compatibility#
Mismatched versions of anchor-cli, anchor-lang, and @otter-sec/anchor can lead to unexpected behavior. This release prints a warning when the three don’t agree.
Explicit overflow-checks flag#
Cargo’s overflow-checks is implicitly off by default. Workspaces scaffolded by anchor init enabled it, but Anchor never enforced the setting on existing workspaces. As of this release, overflow-checks in the workspace Cargo.toml must be set explicitly to either true or false.
Wildcard pattern in Anchor.toml#
workspace.members and workspace.exclude now support a simple trailing wildcard:
[workspace]members = ["programs/*"]More complex glob patterns are not yet supported.
cargo build-sbf is now the default#
Previously anchor build invoked cargo build-bpf. Because build-bpf is deprecated, anchor build now defaults to cargo build-sbf. The old behavior is still available with:
anchor build --arch bpfRun multiple commands in scripts#
Scripts in Anchor.toml now support multiple commands chained with &&:
[scripts]test-all = "cargo test && yarn run ts-mocha tests/**/*.ts"Run the script with:
anchor run test-allTest only a specified program#
A single program in a multi-program workspace can be tested with --program-name (-p):
anchor test --program-name exampleRust test template#
Initialize a workspace with a Rust test template instead of the default TypeScript:
anchor init --test-template rustTypeScript#
Account resolution#
Account resolution lets clients fill in accounts automatically rather than passing every one explicitly. The TS library’s resolution logic has been overhauled. Most of those changes are internal, but the user-facing surface around .accounts() has changed.
Previously, all accounts on the builder were typed as partial, with no way to know which ones the IDL could resolve. The transaction builder now exposes three methods:
.accounts()is fully type-safe against the IDL’s resolution fields, so only the accounts that can’t be resolved need to be passed..accountsPartial()preserves the old behavior, accepting any account including resolvable ones..accountsStrict()opts out of resolution entirely and requires every account to be passed manually (unchanged from before).
Existing .accounts() calls may stop type-checking. Either rename them to .accountsPartial() to keep the old behavior, or drop the accounts the IDL can resolve:
await program.methods .init() .accounts({ pda: ..., signer: ..., systemProgram: ..., }) .rpc()await program.methods.init().rpc()Magic account names#
The TS library no longer autofills common program and sysvar accounts based on field names like systemProgram. The IDL’s new address field resolves programs and sysvars directly, removing the need for the name-based magic.
Case conversion#
The TS library’s internals were riddled with case-conversion logic before string comparisons, forcing libraries built on Anchor to do the same. The IDL and the TS library now both use consistent camelCase throughout.
No more program id#
The programId parameter of Program has been removed. The new IDL stores the program id in its address field:
new Program(idl, programId)new Program(idl)Optional provider options#
The opts parameter of AnchorProvider is now optional:
new AnchorProvider(connection, wallet, {})new AnchorProvider(connection, wallet)Type changes#
Too many type changes to enumerate here, especially around the IDL. See idl.ts for the new types.
See the full list of notable changes in the CHANGELOG.
0.29.0
Anchor release notes for 0.29.0.
Anchor keeps a CHANGELOG.md, but parsing what changed, why it matters, and how to migrate isn’t always obvious from the entries. The release notes provide an actionable, digestible view of each release.
How to update#
-
Update
avm:Terminal window cargo install --git https://github.com/otter-sec/anchor --tag v0.29.0 avm --locked -
Update
anchor-cli:Terminal window avm install latest -
Update Anchor crate(s) to
0.29.0. Optionally runcargo updateto refresh other dependencies to the latest compatible versions. -
Update TS package(s) to
0.29.0.
Solana 1.14 is no longer supported#
The minimum supported Solana version is now 1.16.0. All clusters, including mainnet-beta, are running ^1.16, and a compatibility issue between 1.14 and 1.16 makes staying on the older version impractical. If you are still on 1.14, upgrade with:
solana-install init 1.17.0Override toolchain for the workspace#
Anchor.toml has a new section called [toolchain] that allows overriding the current toolchain versions inside the workspace:
[toolchain]anchor_version = "0.29.0" # `anchor-cli` version to usesolana_version = "1.17.0" # Solana version to useBoth fields are optional. anchor_version requires avm to be installed. Before this release, the anchor_version and solana_version keys in Anchor.toml only affected Docker verifiable builds. Every command now honors the [toolchain] section.
Install CLI from commit with avm#
Installing the CLI from a specific commit was historically possible directly through cargo:
cargo install --git https://github.com/otter-sec/anchor --rev 6cf200493a307c01487c7b492b4893e0d6f6cb23 anchor-cli --lockedThat approach overrides the anchor binary outside of avm’s control. As of this release, avm natively supports installing and switching between commits.
Pass a <version>-<commit> pair, a full commit hash, or a short prefix to avm install:
avm install 0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23avm install 6cf200493a307c01487c7b492b4893e0d6f6cb23avm install 6cf200Activate it with avm use:
avm use 0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23The same identifier also works as the toolchain.anchor_version value in Anchor.toml:
[toolchain]anchor_version = "0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23"Multiple files template#
Programs scaffolded by anchor init and anchor new previously shipped as a single lib.rs. A new template emits the common multi-file layout:
- constants.rs
- error.rs
instructions/
- initialize.rs
- mod.rs
- lib.rs
state/
- mod.rs
Initialize a workspace with this layout:
anchor init <NAME> --template multipleOr add a new program with the same layout to an existing workspace:
anchor new <NAME> --template multipleUpgradeable programs in tests#
Upgradeability for programs run under anchor test is now configurable in Anchor.toml. The workspace-wide flag covers every test program:
[test]upgradeable = trueA [[test.genesis]] entry overrides the flag for an individual program:
[[test.genesis]]address = "22Y43yTVxuUkoRKdm9thyRhQ3SdgQS7c7kB6UNCiaczD"program = "swap.so"upgradeable = trueLamport utilities#
Transferring lamports from a PDA used to require awkward type juggling. The new sub_lamports() and add_lamports() helpers replace the borrow dance:
**ctx.accounts.from.to_account_info().try_borrow_mut_lamports()? -= amount;**ctx.accounts.to.to_account_info().try_borrow_mut_lamports()? += amount;ctx.accounts.from.sub_lamports(amount)?;ctx.accounts.to.add_lamports(amount)?;get_lamports() similarly replaces the read-side dance:
let lamports = ctx.accounts.my_account.to_account_info().lamports();let lamports = ctx.accounts.my_account.get_lamports();These helpers are also more efficient than the manual form. to_account_info() clones the underlying data internally, while the new methods take a reference to it.
Type-safe context bumps#
Before this release, ctx.bumps was a BTreeMap<String, u8>, which gave no type safety for the account-name keys:
let bump = *ctx.bumps.get("my_account").unwrap();It is now an auto-generated struct that holds each bump as a named field, enabling completion and rejecting typos at compile time:
let bump = ctx.bumps.my_account;The struct form is also faster than BTreeMap, which is heap-allocated and occasionally has to resize.
idl-build feature#
IDLs can now be generated via compilation rather than parsing. Enable it by adding the idl-build feature to the program’s Cargo.toml:
[features]idl-build = ["anchor-lang/idl-build"]The IDL will be built automatically when you run anchor build but if you’d like to only generate the IDL, run anchor idl build.
Every crate involved in IDL generation must be added to the idl-build feature list:
[features]idl-build = [ "anchor-lang/idl-build", "anchor-spl/idl-build", "another-program/idl-build"]Compile-time checks are supported, as are external types from other Anchor programs (provided the external crate also exposes an idl-build feature, like another-program/idl-build above). Two crates can use the same type name (for example some_module::MyType and another_module::MyType) without collision. Generation is noticeably slower than the default parsing-based method due to Rust compile times. Most of the pipeline works well, but rough edges remain. If you run into one, please open an issue.
Type aliases#
Anchor IDL now supports type aliases:
pub type U8Array = [u8; 8];
#[program]pub mod my_program { use super::*;
pub fn type_alias(ctx: Context<TypeAlias>, u8_array: U8Array) -> Result<()> { msg!("{:?}", u8_array); Ok(()) }}
#[derive(Accounts)]pub struct TypeAlias {}Generates the following IDL:
{ "version": "0.1.0", "name": "my_program", "instructions": [ { "name": "typeAlias", "accounts": [], "args": [ { "name": "u8Array", "type": { "defined": "U8Array" } } ] } ], "types": [ { "name": "U8Array", "type": { "kind": "alias", "value": { "array": ["u8", 8] } } } ]}This example currently works only with the default parsing-based IDL generator. Type aliases over built-in Rust types are not yet handled correctly by idl-build (#2640).
Export mpl-token-metadata#
anchor-spl with the metadata feature now re-exports the mpl-token-metadata crate. Drop the direct dependency to avoid version conflicts:
[dependencies]anchor-spl = { version = "0.29.0", features = ["metadata"] }mpl-token-metadata = "1.13.1"The crate is reachable through anchor_spl::metadata:
use anchor_spl::metadata::mpl_token_metadata;TypeScript SDK improvements#
Program.addEventListener is now strongly typed. Event names and the event passed to the callback both carry their proper types instead of any.
anchor.workspace lazy-loads programs on demand, so programs that aren’t used in the test suite no longer get loaded or trigger errors.
JavaScript convention uses camelCase for property names, but programs were previously accessed via PascalCase (e.g. anchor.workspace.MyProgram), which is unintuitive. Both variations now work:
const camel = anchor.workspace.myProgramconst pascal = anchor.workspace.MyProgramThe assert and base64-js dependencies have been removed.
New Docker image#
The previous image, projectserum/build, has been deprecated. The new image is backpackapp/build, which you can pull with docker pull backpackapp/build:v0.29.0. anchor build --verifiable works against the new image.
Enhanced performance#
0.29.0 improves performance across the board, most notably reducing binary size by roughly 36% relative to 0.28.0. Similar wins are tracked for compute units and stack memory. Exact numbers vary between programs, but the overall direction is consistent.
See the full list of changes in the CHANGELOG.