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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/reusable-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,8 @@ jobs:
path: tests/declare-id
- cmd: cd tests/declare-program && anchor test --skip-lint
path: tests/declare-program
- cmd: cd tests/custom-program && anchor test --skip-lint
path: tests/custom-program
- cmd: cd tests/typescript && anchor test --skip-lint && npx tsc --noEmit
path: tests/typescript
# zero-copy tests cause `/usr/bin/ld: final link failed: No space left on device`
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- cli: Replace `anchor verify` to use `solana-verify` under the hood, adding automatic installation via AVM, local path support, and future-proof argument passing ([#3768](https://github.com/solana-foundation/anchor/pull/3768)).
- lang: Replace `solana-program` crate with smaller crates ([#3819](https://github.com/solana-foundation/anchor/pull/3819)).
- cli: Make `anchor deploy` to upload the IDL to the cluster by default unless `--no-idl` is passed ([#3863](https://github.com/solana-foundation/anchor/pull/3863)).
- lang: Add generic program validation support to `Program` type allowing `Program<'info>` for executable-only validation ([#3878](https://github.com/solana-foundation/anchor/pull/3878)).
- lang: Use `solana-invoke` instead of `solana_cpi::invoke` ([#3900](https://github.com/solana-foundation/anchor/pull/3900)).
- client: remove `solana-client` from `anchor-client` and `cli` ([#3877](https://github.com/solana-foundation/anchor/pull/3877)).
- idl: Build IDL on stable Rustc ([#3842](https://github.com/solana-foundation/anchor/pull/3842)).
Expand Down Expand Up @@ -616,7 +617,7 @@ See the [Anchor 0.29 release notes](https://www.anchor-lang.com/release-notes/0.
- spl: Re-export the `spl_token` crate ([#1665](https://github.com/coral-xyz/anchor/pull/1665)).
- lang, cli, spl: Update solana toolchain to v1.9.13 ([#1653](https://github.com/coral-xyz/anchor/pull/1653) and [#1751](https://github.com/coral-xyz/anchor/pull/1751)).
- lang: `Program` type now deserializes `programdata_address` only on demand ([#1723](https://github.com/coral-xyz/anchor/pull/1723)).
- ts: Make `Provider` an interface and adjust its signatures and add `AnchorProvider` implementor class ([#1707](https://github.com/coral-xyz/anchor/pull/1707)).
- ts: Make `Provider` an interface and adjust its signatures and add `AnchorProvider` implementer class ([#1707](https://github.com/coral-xyz/anchor/pull/1707)).
- spl: Change "to" to "from" in `token::burn` ([#1080](https://github.com/coral-xyz/anchor/pull/1080)).

## [0.23.0] - 2022-03-20
Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ To jump straight to examples, go [here](https://github.com/coral-xyz/anchor/tree
| `anchor-spl` | CPI clients for SPL programs on Solana | [![crates](https://img.shields.io/crates/v/anchor-spl?color=blue)](https://crates.io/crates/anchor-spl) | [![Docs.rs](https://docs.rs/anchor-spl/badge.svg)](https://docs.rs/anchor-spl) |
| `anchor-client` | Rust client for Anchor programs | [![crates](https://img.shields.io/crates/v/anchor-client?color=blue)](https://crates.io/crates/anchor-client) | [![Docs.rs](https://docs.rs/anchor-client/badge.svg)](https://docs.rs/anchor-client) |
| `@coral-xyz/anchor` | TypeScript client for Anchor programs | [![npm](https://img.shields.io/npm/v/@coral-xyz/anchor.svg?color=blue)](https://www.npmjs.com/package/@coral-xyz/anchor) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://coral-xyz.github.io/anchor/ts/index.html) |
| `@coral-xyz/anchor-cli` | CLI to support building and managing an Anchor workspace | [![npm](https://img.shields.io/npm/v/@coral-xyz/anchor-cli.svg?color=blue)](https://www.npmjs.com/package/@coral-xyz/anchor-cli) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://coral-xyz.github.io/anchor/cli/commands.html) |
| `@coral-xyz/anchor-cli` | CLI to support building and managing an Anchor workspace | [![npm](https://img.shields.io/npm/v/@coral-xyz/anchor-cli.svg?color=blue)](https://www.npmjs.com/package/@coral-xyz/anchor-cli) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://www.anchor-lang.com/docs/references/cli) |

## Note

Expand Down
2 changes: 1 addition & 1 deletion avm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ mod tests {
let expected = vec![version];
assert_eq!(read_installed_versions().unwrap(), expected);

// Should ignore this file because its not anchor- prefixed
// Should ignore this file because it's not anchor- prefixed
fs::File::create(AVM_HOME.join("bin").join("garbage").as_path()).unwrap();
assert_eq!(read_installed_versions().unwrap(), expected);
}
Expand Down
2 changes: 1 addition & 1 deletion bench/BINARY_SIZE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Solana version: 2.3.0

| Program | Binary Size | - |
| ------- | ----------- | ----------------------- |
| bench | 1,024,096 | 🟢 **-102,744 (9.12%)** |
| bench | 1,024,112 | 🟢 **-102,728 (9.12%)** |

### Notable changes

Expand Down
6 changes: 3 additions & 3 deletions bench/COMPUTE_UNITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,9 @@ Solana version: 2.1.0
| interface4 | 1,189 | - |
| interface8 | 1,748 | - |
| program1 | 779 | - |
| program2 | 920 | - |
| program4 | 1,193 | - |
| program8 | 1,744 | - |
| program2 | 934 | 🔴 **+14 (1.52%)** |
| program4 | 1,221 | 🔴 **+28 (2.35%)** |
| program8 | 1,800 | 🔴 **+56 (3.21%)** |
| signer1 | 774 | - |
| signer2 | 1,064 | - |
| signer4 | 1,637 | - |
Expand Down
2 changes: 1 addition & 1 deletion client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]

//! An RPC client to interact with Solana programs written in [`anchor_lang`].
//!
Expand Down
4 changes: 2 additions & 2 deletions docs/content/docs/basics/cpi.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description:
---

Cross Program Invocations (CPI) refer to the process of one program invoking
instructions of another program, which enables the composibility of Solana
instructions of another program, which enables the composability of Solana
programs.

This section will cover the basics of implementing CPIs in an Anchor program,
Expand Down Expand Up @@ -98,7 +98,7 @@ resulting in a successful SOL transfer.

Cross Program Invocations (CPIs) allow one program to invoke instructions on
another program. The process of implementing a CPI is the same as that of
creating a instruction where you must specify:
creating an instruction where you must specify:

1. The program ID of the program being called
2. The accounts required by the instruction
Expand Down
4 changes: 2 additions & 2 deletions docs/content/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ To verify that the installation was successful, check the Yarn version:
yarn --version
```

You should the following output:
You should see the following output:

```
1.22.1
Expand Down Expand Up @@ -567,7 +567,7 @@ Keypair Path: /Users/test/.config/solana/id.json
Commitment: confirmed
```

The RPC URL and Websocket URL specific the Solana cluster the CLI will make
The RPC URL and Websocket URL specify the Solana cluster the CLI will make
requests to. By default this will be mainnet-beta.

You can update the Solana CLI cluster using the following commands:
Expand Down
2 changes: 1 addition & 1 deletion docs/content/docs/tokens/basics/transfer-tokens.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ describe("token-example", () => {
console.log("Mint Account", mintAccount);
});

it("Mint Tokens", async () => {
it("Transfer Tokens", async () => {
const tx = await program.methods
.transferTokens()
.accounts({
Expand Down
6 changes: 3 additions & 3 deletions docs/content/docs/updates/release-notes/0-31-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Program name: `my-program`
### Pass `cargo` args to IDL build

Both `anchor build` and `anchor idl build` commands pass the `cargo` arguments
to the underyling IDL build command. For example:
to the underlying IDL build command. For example:

```
anchor build -- --features my-feature
Expand Down Expand Up @@ -274,7 +274,7 @@ still allows empty discriminators because some non-Anchor programs, e.g. the SPL
Token program, don't have account discriminators. In that case, safety checks
should never depend on the discriminator.

Additionally, the IDL generation step also checks whether you have ambigious
Additionally, the IDL generation step also checks whether you have ambiguous
discriminators i.e. discriminators that can be used for multiple types. However,
you should still consider future possibilities, especially when working with
1-byte discriminators. For example, having an account with discriminator `[1]`
Expand Down Expand Up @@ -440,7 +440,7 @@ Building the IDL via the
[`build_idl`](https://github.com/coral-xyz/anchor/blob/v0.31.0/idl/src/build.rs#L119)
function made it impossible to extend its functionality e.g. add new parameters
without a breaking change. To solve this problem, there is a new way to build
IDLs programatically:
IDLs programmatically:

```rs
let idl = IdlBuilder::new().program_path(path).skip_lint(true).build()?;
Expand Down
2 changes: 1 addition & 1 deletion lang/attribute/account/src/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn gen_lazy(strct: &syn::ItemStruct) -> syn::Result<TokenStream> {
let load_panic_docs = quote! {
/// # Panics
///
/// If there is an existing mutable reference crated by any of the `load_mut` methods.
/// If there is an existing mutable reference created by any of the `load_mut` methods.
};
let load_mut_panic_docs = quote! {
/// # Panics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ fn gen_internal_args_mod(idl: &Idl) -> proc_macro2::TokenStream {
/// An Anchor generated module containing the program's set of instructions, where each
/// method handler in the `#[program]` mod is associated with a struct defining the input
/// arguments to the method. These should be used directly, when one wants to serialize
/// Anchor instruction data, for example, when specifying instructions instructions on a
/// Anchor instruction data, for example, when specifying instructions on a
/// client.
pub mod args {
use super::*;
Expand Down
39 changes: 35 additions & 4 deletions lang/src/accounts/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,28 @@ use std::ops::Deref;
///
/// The type has a `programdata_address` function that will return `Option::Some`
/// if the program is owned by the [`BPFUpgradeableLoader`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/index.html)
/// which will contain the `programdata_address` property of the `Program` variant of the [`UpgradeableLoaderState`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/enum.UpgradeableLoaderState.html) enum.
/// which will contain the `programdata_address` property of the `Program` variant of the [`UpgradeableLoaderState`](https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface/state/enum.UpgradeableLoaderState.html) enum.
///
/// # Table of Contents
/// - [Basic Functionality](#basic-functionality)
/// - [Generic Program Validation](#generic-program-validation)
/// - [Out of the Box Types](#out-of-the-box-types)
///
/// # Basic Functionality
///
/// For `Program<'info, T>` where T implements Id:
/// Checks:
///
/// - `account_info.key == expected_program`
/// - `account_info.executable == true`
///
/// # Generic Program Validation
///
/// For `Program<'info>` (without type parameter):
/// - Only checks: `account_info.executable == true`
/// - Use this when you only need to verify that an address is executable,
/// without validating against a specific program ID.
///
/// # Example
/// ```ignore
/// #[program]
Expand Down Expand Up @@ -65,6 +74,16 @@ use std::ops::Deref;
/// - `program_data`'s constraint checks that its upgrade authority is the `authority` account.
/// - Finally, `authority` needs to sign the transaction.
///
/// ## Generic Program Example
/// ```ignore
/// #[derive(Accounts)]
/// pub struct ValidateExecutableProgram<'info> {
/// // Only validates that the provided account is executable
/// pub any_program: Program<'info>,
/// pub authority: Signer<'info>,
/// }
/// ```
///
/// # Out of the Box Types
///
/// Between the [`anchor_lang`](https://docs.rs/anchor-lang/latest/anchor_lang) and [`anchor_spl`](https://docs.rs/anchor_spl/latest/anchor_spl) crates,
Expand All @@ -75,7 +94,7 @@ use std::ops::Deref;
/// - [`Token`](https://docs.rs/anchor-spl/latest/anchor_spl/token/struct.Token.html)
///
#[derive(Clone)]
pub struct Program<'info, T> {
pub struct Program<'info, T = ()> {
info: &'info AccountInfo<'info>,
_phantom: PhantomData<T>,
}
Expand Down Expand Up @@ -128,13 +147,15 @@ impl<'a, T: Id> TryFrom<&'a AccountInfo<'a>> for Program<'a, T> {
type Error = Error;
/// Deserializes the given `info` into a `Program`.
fn try_from(info: &'a AccountInfo<'a>) -> Result<Self> {
if info.key != &T::id() {
// Special handling for unit type () - only check executable, not program ID
let is_unit_type = T::id() == Pubkey::default();

if !is_unit_type && info.key != &T::id() {
return Err(Error::from(ErrorCode::InvalidProgramId).with_pubkeys((*info.key, T::id())));
}
if !info.executable {
return Err(ErrorCode::InvalidProgramExecutable.into());
}

Ok(Program::new(info))
}
}
Expand Down Expand Up @@ -195,3 +216,13 @@ impl<T: AccountDeserialize> Key for Program<'_, T> {
*self.info.key
}
}

// Implement Id trait for unit type to support Program<'info> without type parameter
impl crate::Id for () {
fn id() -> Pubkey {
// For generic programs, this should never be called since they don't validate specific program IDs.
// However, we need to implement it to satisfy the trait bounds.
// Using a special marker value that indicates "any program"
Pubkey::default()
}
}
2 changes: 1 addition & 1 deletion lang/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]

//! Anchor ⚓ is a framework for Solana's Sealevel runtime providing several
//! convenient developer tools.
Expand Down
4 changes: 2 additions & 2 deletions lang/syn/src/codegen/accounts/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1660,7 +1660,7 @@ fn generate_get_token_account_space(mint: &Expr) -> proc_macro2::TokenStream {
}
}

// Generated code to create an account with with system program with the
// Generated code to create an account with system program with the
// given `space` amount of data, owned by `owner`.
//
// `seeds_with_nonce` should be given for creating PDAs. Otherwise it's an
Expand Down Expand Up @@ -1729,7 +1729,7 @@ pub fn generate_constraint_executable(
let name_str = f.ident.to_string();
let account_ref = generate_account_ref(f);

// because we are only acting on the field, we know it isnt optional at this point
// because we are only acting on the field, we know it isn't optional at this point
// as it was unwrapped in `generate_constraint`
quote! {
if !#account_ref.executable {
Expand Down
15 changes: 11 additions & 4 deletions lang/syn/src/idl/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,17 @@ fn get_address(acc: &Field) -> TokenStream {
match &acc.ty {
Ty::Program(_) | Ty::Sysvar(_) => {
let ty = acc.account_ty();
let id_trait = matches!(acc.ty, Ty::Program(_))
.then(|| quote!(anchor_lang::Id))
.unwrap_or_else(|| quote!(anchor_lang::solana_program::sysvar::SysvarId));
quote! { Some(<#ty as #id_trait>::id().to_string()) }
// Check if this is the unit type marker (for generic Program<'info>)
let ty_str = quote!(#ty).to_string();
if ty_str == "" || ty_str == "__SolanaProgramUnitType" {
// For generic programs, we don't have a specific address
quote! { None }
} else {
let id_trait = matches!(acc.ty, Ty::Program(_))
.then(|| quote!(anchor_lang::Id))
.unwrap_or_else(|| quote!(anchor_lang::solana_program::sysvar::SysvarId));
quote! { Some(<#ty as #id_trait>::id().to_string()) }
}
}
_ => acc
.constraints
Expand Down
26 changes: 23 additions & 3 deletions lang/syn/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod codegen;
pub mod parser;
Expand Down Expand Up @@ -344,6 +344,20 @@ impl Field {
Sysvar<#account>
}
}
Ty::Program(ty) => {
let program = &ty.account_type_path;
// Check if this is the generic Program<'info> (unit type)
let program_str = quote!(#program).to_string();
if program_str == "__SolanaProgramUnitType" {
quote! {
#container_ty<'info>
}
} else {
quote! {
#container_ty<'info, #program>
}
}
}
_ => quote! {
#container_ty<#account_ty>
},
Expand Down Expand Up @@ -543,8 +557,14 @@ impl Field {
},
Ty::Program(ty) => {
let program = &ty.account_type_path;
quote! {
#program
// Check if this is the special marker for generic Program<'info> (unit type)
let program_str = quote!(#program).to_string();
if program_str == "__SolanaProgramUnitType" {
quote! {}
} else {
quote! {
#program
}
}
}
Ty::Interface(ty) => {
Expand Down
Loading