Skip to main content

Release Notes 0.29.0

Anchor keeps a CHANGELOG but it's not easy to make sense what has changed, what effect does the change have and how to migrate. This is where release notes comes in, an easy to digest and actionable view for each release.


How to update

  1. Update avm:

    cargo install --git https://github.com/coral-xyz/anchor --tag v0.29.0 avm --locked
  2. Update anchor-cli:

    avm install latest
  3. Update Anchor crate(s) to 0.29.0. Optionally, run cargo update to update other dependencies to the latest compatible versions.

  4. Update TS package(s) to 0.29.0.

Solana 1.14 is no longer supported

Minimum supported Solana version is now 1.16.0 because

  • All clusters including mainnet-beta are now running ^1.16
  • There is a compatibility issue between 1.14 and 1.16

If you are still on Solana 1.14, update by running:

solana-install init 1.17.0

Override 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 use
solana_version = "1.17.0" # Solana version to use

Notes

  • Fields are optional.
  • anchor_version requires avm to be installed.
  • Before this release, anchor_version and solana_version keys in Anchor.toml were being used for Docker verifiable builds only. Now, all commands work via the [toolchain] section.

Install CLI from commit with avm

It is possible to install CLI from commit by running:

cargo install --git https://github.com/coral-xyz/anchor --rev 6cf200493a307c01487c7b492b4893e0d6f6cb23 anchor-cli --locked

but this overrides the anchor binary and does not work well with avm.

In this release, avm supports installing and switching between commits.

Install from a commit with avm install <VERSION>-<COMMIT>:

# <VERSION>-<COMMIT>
avm install 0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23

# Full commit hash
avm install 6cf200493a307c01487c7b492b4893e0d6f6cb23

# Short commit hash
avm install 6cf200

Use a different version avm use <VERSION>-<COMMIT>:

avm use 0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23

Specify toolchain.anchor_version as <VERSION>-<COMMIT>:

[toolchain]
anchor_version = "0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23"

Multiple files template

Programs created with anchor init or anchor new have a single lib.rs file but not everyone prefers a single file approach for programs.

The most popular way of splitting the program into multiple files looks something like the following:

├── constants.rs
├── error.rs
├── instructions
│   ├── initialize.rs
│   └── mod.rs
├── lib.rs
└── state
└── mod.rs

To initialize a workspace with this program structure, run:

anchor init <NAME> --template multiple

or if you have an existing workspace:

anchor new <NAME> --template multiple

Upgradeable programs in tests

You can now configure upgradability of the programs in anchor test.

In Anchor.toml:

[test]
upgradeable = true

or for an individual program:

[[test.genesis]]
address = "22Y43yTVxuUkoRKdm9thyRhQ3SdgQS7c7kB6UNCiaczD"
program = "swap.so"
upgradeable = true

Lamport utilities

Transferring lamports from a PDA is quite complicated due to the types that are being used.

Instead of

**ctx.accounts.from.to_account_info().try_borrow_mut_lamports()? -= amount;
**ctx.accounts.to.to_account_info().try_borrow_mut_lamports()? += amount;

you can

ctx.accounts.from.sub_lamports(amount)?;
ctx.accounts.to.add_lamports(amount)?;

Similarly for getting the lamports, instead of

let lamports = ctx.accounts.my_account.to_account_info().lamports();

you can

let lamports = ctx.accounts.my_account.get_lamports();

Note: The new methods are not only more ergonomic but they are also more performant than the previous examples. This is because to_account_info method clones the data internally but the new methods use a reference to the underlying data.

Type safe context bumps

Before this release, ctx.bumps used to be a BTreeMap<String, u8> which doesn't provide type safety for the keys(account names).

let bump = *ctx.bumps.get("my_account").unwrap();

With this release, there is an auto-generated struct that holds the bump values.

let bump = ctx.bumps.my_account;

Note: The new way is not only more intuitive but also is more performant. This is mainly because BTreeMap is heap-allocated and it has to resize and grow occasionally.

idl-build feature

There is a new way to generate IDLs via compilation.

Add idl-build feature to your program's Cargo.toml to try it out.

[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

Notes

  • All crates that are being used for the IDL generation needs to 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.
  • External types from other Anchor programs are supported as long as the external crate has the idl-build feature(see another-program/idl-build).
  • Conflicting type names e.g. some_module::MyType and another_module::MyType can be used together.
  • Generation time is a lot slower compared to the default method(parsing) due to Rust compile times.
  • Even though most of it works great, some parts are still rough around the edges and you may encounter parts that are not fully ironed out. Please create an issue if you run into a problem.

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]
}
}
}
]
}

Note: This example only works with the default IDL generation method(parsing) for now because type aliases for default Rust types don't work properly with idl-build(#2640).

Export mpl-token-metadata

anchor-spl with metadata feature enabled now exports the mpl-token-metadata crate.

Note: Consider removing the mpl-token-metadata dependency to reduce the possibility of having conflicting versions:

[dependencies]
anchor-spl = { version = "0.29.0", features = ["metadata"] }
- mpl-token-metadata = "1.13.1"

and use the exported crate from anchor-spl:

use anchor_spl::metadata::mpl_token_metadata;

TypeScript SDK improvements

  1. Program.addEventListener method is now strongly typed -- correct types for the event names and the event returned from the callback instead of any.

  2. anchor.workspace now lazy loads programs on-demand. Programs that are not being used in the tests won't get loaded and therefore won't cause errors.

  3. JavaScript convention is to use camelCase for property names but programs are accessed via PascalCase e.g. anchor.workspace.MyProgram which is unintuitive. Both variations work in this release.

    const camel = anchor.workspace.myProgram
    const pascal = anchor.workspace.MyProgram
  4. Removed assert and base64-js dependency.

New docker image

The previous image(projectserum/build) is now deprecated, new image is backpackapp/build.

To pull the latest image, run:

docker pull backpackapp/build:v0.29.0

Note: anchor build --verifiable now works with the latest image.

Enhanced performance

0.29.0 performance is noticeably improved in all areas, the biggest one being binary size which is reduced ~36% compared to 0.28.0!

Similar benchmarks can be found for compute units and stack memory.

Note: The benchmark results will vary between programs but the overall direction should be the same.


See the full list of changes in the CHANGELOG.