Compare commits

...

21 Commits

Author SHA1 Message Date
cavemanloverboy 1d65b1a30d
Merge c51a838aa4 into 95c4959287 2024-04-14 22:35:07 +02:00
acheron 95c4959287
ts: Add missing errors (#2906) 2024-04-14 00:00:41 +02:00
Bhargava Sai Macha a18d6caa6d
spl: Make `TokenAccount` and `Mint` `Copy` (#2904) 2024-04-13 23:30:02 +02:00
acheron 7356bd5afe
idl: Keep crate and `spec` version the same (#2901) 2024-04-13 01:06:45 +02:00
acheron 1f0bf0ee60
spl: Remove `solana-program` dependency (#2900) 2024-04-11 23:57:41 +02:00
Bhargava Sai Macha e3ced784ad
Add support for token extensions (#2789) 2024-04-11 22:49:13 +02:00
acheron ae26fd84bb
spl: Upgrade `mpl-token-metadata` to 4.1.2 (#2899) 2024-04-10 23:58:13 +02:00
acheron 0be5b00a34
lang: Add `Event` utility type to get events from bytes (#2897) 2024-04-09 23:57:41 +02:00
acheron c7ccbb8f62
Fix `1.79.0-nightly` warnings (#2896) 2024-04-08 23:58:45 +02:00
acheron 3591ba6cb8
spl: Remove `toml_edit` version requirement (#2895) 2024-04-08 21:19:34 +02:00
acheron 01839ad725
lang: Add composite accounts support for `declare_program!` (#2894) 2024-04-07 23:41:56 +02:00
acheron cbf9b0a090
Unpin `nightly` version (#2893) 2024-04-07 13:47:50 +02:00
acheron da2d9a4045
idl: Store deployment addresses for other clusters (#2892) 2024-04-06 23:39:53 +02:00
acheron 2dd79da674
spl: Upgrade `spl-associated-token-account` to 3.0.2 (#2891) 2024-04-05 23:18:46 +02:00
acheron 5f6af05519
idl: Add `#[non_exhaustive]` to IDL enums (#2890) 2024-04-04 22:34:35 +02:00
acheron 4de70aabee
idl: Add `docs` field for constants (#2887) 2024-04-03 21:59:43 +02:00
acheron c138a55b72
idl: Move IDL types from the `anchor-syn` crate to the new IDL crate (#2882) 2024-04-02 20:01:27 +02:00
cavemanloverboy c51a838aa4
remove one more Deref import 2023-11-18 13:18:58 -08:00
cavemanloverboy 9e5bfe18ae
remove Deref import 2023-11-18 13:15:18 -08:00
cavemanloverboy 12349b4a2f
update nonblocking client 2023-11-18 13:14:57 -08:00
cavemanloverboy 1644bc8623
impl signer now includes deref impl signer 2023-11-18 11:23:06 -08:00
114 changed files with 3664 additions and 837 deletions

View File

@ -9,12 +9,3 @@ runs:
shell: bash
- run: git submodule update --init --recursive --depth 1
shell: bash
# `nightly` toolchain is currently required for building the IDL.
#
# Pinning the toolchain to an older date in order to fix
# `error[E0635]: unknown feature stdsimd` error from `ahash`.
# See: https://github.com/tkaitchuck/aHash/issues/200
#
# TODO: Unpin `nightly` release after upgrading Solana to `1.18`.
- run: rustup toolchain install nightly-2024-01-30
shell: bash

View File

@ -388,6 +388,8 @@ jobs:
path: spl/token-wrapper
- cmd: cd tests/spl/transfer-hook && anchor test --skip-lint
path: spl/transfer-hook
- cmd: cd tests/spl/token-extensions && anchor test --skip-lint
path: spl/token-extensions
- cmd: cd tests/multisig && anchor test --skip-lint
path: tests/multisig
# - cmd: cd tests/lockup && anchor test --skip-lint

View File

@ -40,6 +40,10 @@ The minor version will be incremented upon a breaking change and the patch versi
- ts: Add `prepend` option to MethodBuilder `preInstructions` method ([#2863](https://github.com/coral-xyz/anchor/pull/2863)).
- lang: Add `declare_program!` macro ([#2857](https://github.com/coral-xyz/anchor/pull/2857)).
- cli: Add `deactivate_feature` flag to `solana-test-validator` config in Anchor.toml ([#2872](https://github.com/coral-xyz/anchor/pull/2872)).
- idl: Add `docs` field for constants ([#2887](https://github.com/coral-xyz/anchor/pull/2887)).
- idl: Store deployment addresses for other clusters ([#2892](https://github.com/coral-xyz/anchor/pull/2892)).
- lang: Add `Event` utility type to get events from bytes ([#2897](https://github.com/coral-xyz/anchor/pull/2897)).
- lang, spl: Add support for [token extensions](https://solana.com/solutions/token-extensions) ([#2789](https://github.com/coral-xyz/anchor/pull/2789)).
### Fixes
@ -66,6 +70,9 @@ The minor version will be incremented upon a breaking change and the patch versi
- client: Fix `parse_logs_response` to prevent panics when more than 1 outer instruction exists in logs ([#2856](https://github.com/coral-xyz/anchor/pull/2856)).
- avm, cli: Fix `stdsimd` feature compilation error from `ahash` when installing the CLI using newer Rust versions ([#2867](https://github.com/coral-xyz/anchor/pull/2867)).
- spl: Fix not being able to deserialize newer token 2022 extensions ([#2876](https://github.com/coral-xyz/anchor/pull/2876)).
- spl: Remove `solana-program` dependency ([#2900](https://github.com/coral-xyz/anchor/pull/2900)).
- spl: Make `TokenAccount` and ` Mint` `Copy` ([#2904](https://github.com/coral-xyz/anchor/pull/2904)).
- ts: Add missing errors ([#2906](https://github.com/coral-xyz/anchor/pull/2906)).
### Breaking
@ -87,6 +94,8 @@ The minor version will be incremented upon a breaking change and the patch versi
- ts: `Program` instances use camelCase for everything ([#2824](https://github.com/coral-xyz/anchor/pull/2824)).
- ts: Remove discriminator functions ([#2824](https://github.com/coral-xyz/anchor/pull/2824)).
- ts: Remove `programId` parameter of the `Program` constructor ([#2864](https://github.com/coral-xyz/anchor/pull/2864)).
- idl, syn: Move IDL types from the `anchor-syn` crate to the new IDL crate ([#2882](https://github.com/coral-xyz/anchor/pull/2882)).
- idl: Add `#[non_exhaustive]` to IDL enums ([#2890](https://github.com/coral-xyz/anchor/pull/2890)).
## [0.29.0] - 2023-10-16

50
Cargo.lock generated
View File

@ -170,6 +170,7 @@ dependencies = [
name = "anchor-attribute-program"
version = "0.29.0"
dependencies = [
"anchor-idl",
"anchor-syn",
"anyhow",
"bs58 0.5.0",
@ -264,7 +265,7 @@ dependencies = [
[[package]]
name = "anchor-idl"
version = "0.29.0"
version = "0.1.0"
dependencies = [
"anchor-syn",
"anyhow",
@ -286,7 +287,7 @@ dependencies = [
"anchor-derive-accounts",
"anchor-derive-serde",
"anchor-derive-space",
"anchor-syn",
"anchor-idl",
"arrayref",
"base64 0.21.7",
"bincode",
@ -305,12 +306,13 @@ dependencies = [
"borsh 0.10.3",
"mpl-token-metadata",
"serum_dex",
"solana-program",
"spl-associated-token-account",
"spl-associated-token-account 3.0.2",
"spl-memo",
"spl-pod 0.2.2",
"spl-token 4.0.0",
"spl-token-2022 3.0.2",
"toml_edit 0.21.0",
"spl-token-group-interface 0.2.3",
"spl-token-metadata-interface 0.3.3",
]
[[package]]
@ -2530,9 +2532,9 @@ dependencies = [
[[package]]
name = "mpl-token-metadata"
version = "3.1.0"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177204bbe7486b22ac35af2c91a82630f830a6ddd3392651aefde1ef346aba3d"
checksum = "caf0f61b553e424a6234af1268456972ee66c2222e1da89079242251fa7479e5"
dependencies = [
"borsh 0.10.3",
"num-derive 0.3.3",
@ -4522,7 +4524,7 @@ dependencies = [
"serde_json",
"solana-account-decoder",
"solana-sdk",
"spl-associated-token-account",
"spl-associated-token-account 2.3.0",
"spl-memo",
"spl-token 4.0.0",
"spl-token-2022 1.0.0",
@ -4682,6 +4684,22 @@ dependencies = [
"thiserror",
]
[[package]]
name = "spl-associated-token-account"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2e688554bac5838217ffd1fab7845c573ff106b6336bf7d290db7c98d5a8efd"
dependencies = [
"assert_matches",
"borsh 1.3.1",
"num-derive 0.4.0",
"num-traits",
"solana-program",
"spl-token 4.0.0",
"spl-token-2022 3.0.2",
"thiserror",
]
[[package]]
name = "spl-discriminator"
version = "0.1.0"
@ -4763,9 +4781,9 @@ dependencies = [
[[package]]
name = "spl-pod"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079"
checksum = "85a5db7e4efb1107b0b8e52a13f035437cdcb36ef99c58f6d467f089d9b2915a"
dependencies = [
"borsh 0.10.3",
"bytemuck",
@ -4846,7 +4864,7 @@ dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator 0.1.0",
"spl-pod 0.1.0",
"spl-pod 0.1.1",
"spl-program-error 0.3.0",
"spl-type-length-value 0.3.0",
]
@ -4910,7 +4928,7 @@ dependencies = [
"solana-security-txt",
"solana-zk-token-sdk",
"spl-memo",
"spl-pod 0.1.0",
"spl-pod 0.1.1",
"spl-token 4.0.0",
"spl-token-group-interface 0.1.0",
"spl-token-metadata-interface 0.2.0",
@ -4952,7 +4970,7 @@ dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator 0.1.0",
"spl-pod 0.1.0",
"spl-pod 0.1.1",
"spl-program-error 0.3.0",
]
@ -4978,7 +4996,7 @@ dependencies = [
"borsh 0.10.3",
"solana-program",
"spl-discriminator 0.1.0",
"spl-pod 0.1.0",
"spl-pod 0.1.1",
"spl-program-error 0.3.0",
"spl-type-length-value 0.3.0",
]
@ -5007,7 +5025,7 @@ dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator 0.1.0",
"spl-pod 0.1.0",
"spl-pod 0.1.1",
"spl-program-error 0.3.0",
"spl-tlv-account-resolution 0.5.1",
"spl-type-length-value 0.3.0",
@ -5038,7 +5056,7 @@ dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator 0.1.0",
"spl-pod 0.1.0",
"spl-pod 0.1.1",
"spl-program-error 0.3.0",
]

View File

@ -17,7 +17,7 @@ dev = []
[dependencies]
anchor-client = { path = "../client", version = "0.29.0" }
anchor-idl = { path = "../idl", features = ["build"], version = "0.29.0" }
anchor-idl = { path = "../idl", features = ["build"], version = "0.1.0" }
anchor-lang = { path = "../lang", version = "0.29.0" }
anyhow = "1.0.32"
base64 = "0.21"

View File

@ -2964,6 +2964,7 @@ fn deserialize_idl_type_to_json(
deserialize_idl_defined_type_to_json(parent_idl, name, data)?
}
IdlType::Generic(generic) => json!(generic),
_ => unimplemented!("{idl_type:?}"),
})
}

View File

@ -8,7 +8,7 @@ use solana_sdk::{
commitment_config::CommitmentConfig, signature::Signature, signer::Signer,
transaction::Transaction,
};
use std::{marker::PhantomData, ops::Deref, sync::Arc};
use std::{marker::PhantomData, sync::Arc};
use tokio::{
runtime::{Builder, Handle},
sync::RwLock,
@ -21,7 +21,7 @@ impl<'a> EventUnsubscriber<'a> {
}
}
impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
impl<C: Signer + Clone> Program<C> {
pub fn new(program_id: Pubkey, cfg: Config<C>) -> Result<Self, ClientError> {
let rt: tokio::runtime::Runtime = Builder::new_multi_thread().enable_all().build()?;
@ -70,7 +70,7 @@ impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
}
}
impl<'a, C: Deref<Target = impl Signer> + Clone> RequestBuilder<'a, C> {
impl<'a, C: Signer + Clone> RequestBuilder<'a, C> {
pub fn from(
program_id: Pubkey,
cluster: &str,

View File

@ -88,7 +88,6 @@ use solana_sdk::signature::{Signature, Signer};
use solana_sdk::transaction::Transaction;
use std::iter::Map;
use std::marker::PhantomData;
use std::ops::Deref;
use std::pin::Pin;
use std::sync::Arc;
use std::vec::IntoIter;
@ -125,7 +124,7 @@ pub struct Client<C> {
cfg: Config<C>,
}
impl<C: Clone + Deref<Target = impl Signer>> Client<C> {
impl<C: Clone + Signer> Client<C> {
pub fn new(cluster: Cluster, payer: C) -> Self {
Self {
cfg: Config {
@ -157,35 +156,35 @@ impl<C: Clone + Deref<Target = impl Signer>> Client<C> {
}
}
/// Auxiliary data structure to align the types of the Solana CLI utils with Anchor client.
/// Client<C> implementation requires <C: Clone + Deref<Target = impl Signer>> which does not comply with Box<dyn Signer>
/// that's used when loaded Signer from keypair file. This struct is used to wrap the usage.
pub struct DynSigner(pub Arc<dyn Signer>);
// /// Auxiliary data structure to align the types of the Solana CLI utils with Anchor client.
// /// Client<C> implementation requires <C: Clone + impl Signer> which does not comply with Box<dyn Signer>
// /// that's used when loaded Signer from keypair file. This struct is used to wrap the usage.
// pub struct DynSigner(pub Arc<dyn Signer>);
impl Signer for DynSigner {
fn pubkey(&self) -> Pubkey {
self.0.pubkey()
}
// impl Signer for DynSigner {
// fn pubkey(&self) -> Pubkey {
// self.0.pubkey()
// }
fn try_pubkey(&self) -> Result<Pubkey, solana_sdk::signer::SignerError> {
self.0.try_pubkey()
}
// fn try_pubkey(&self) -> Result<Pubkey, solana_sdk::signer::SignerError> {
// self.0.try_pubkey()
// }
fn sign_message(&self, message: &[u8]) -> solana_sdk::signature::Signature {
self.0.sign_message(message)
}
// fn sign_message(&self, message: &[u8]) -> solana_sdk::signature::Signature {
// self.0.sign_message(message)
// }
fn try_sign_message(
&self,
message: &[u8],
) -> Result<solana_sdk::signature::Signature, solana_sdk::signer::SignerError> {
self.0.try_sign_message(message)
}
// fn try_sign_message(
// &self,
// message: &[u8],
// ) -> Result<solana_sdk::signature::Signature, solana_sdk::signer::SignerError> {
// self.0.try_sign_message(message)
// }
fn is_interactive(&self) -> bool {
self.0.is_interactive()
}
}
// fn is_interactive(&self) -> bool {
// self.0.is_interactive()
// }
// }
// Internal configuration for a client.
#[derive(Debug)]
@ -222,7 +221,7 @@ pub struct Program<C> {
rt: tokio::runtime::Runtime,
}
impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
impl<C: Signer + Clone> Program<C> {
pub fn payer(&self) -> Pubkey {
self.cfg.payer.pubkey()
}
@ -519,7 +518,7 @@ pub struct RequestBuilder<'a, C> {
handle: &'a Handle,
}
impl<'a, C: Deref<Target = impl Signer> + Clone> RequestBuilder<'a, C> {
impl<'a, C: Signer + Clone> RequestBuilder<'a, C> {
#[must_use]
pub fn payer(mut self, payer: C) -> Self {
self.payer = payer;
@ -618,7 +617,7 @@ impl<'a, C: Deref<Target = impl Signer> + Clone> RequestBuilder<'a, C> {
) -> Result<Transaction, ClientError> {
let instructions = self.instructions()?;
let mut signers = self.signers.clone();
signers.push(&*self.payer);
signers.push(&self.payer);
let tx = Transaction::new_signed_with_payer(
&instructions,

View File

@ -8,7 +8,7 @@ use solana_sdk::{
commitment_config::CommitmentConfig, signature::Signature, signer::Signer,
transaction::Transaction,
};
use std::{marker::PhantomData, ops::Deref, sync::Arc};
use std::{marker::PhantomData, sync::Arc};
use tokio::sync::RwLock;
impl<'a> EventUnsubscriber<'a> {
@ -18,7 +18,7 @@ impl<'a> EventUnsubscriber<'a> {
}
}
impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
impl<C: Signer + Clone> Program<C> {
pub fn new(program_id: Pubkey, cfg: Config<C>) -> Result<Self, ClientError> {
Ok(Self {
program_id,
@ -66,7 +66,7 @@ impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
}
}
impl<'a, C: Deref<Target = impl Signer> + Clone> RequestBuilder<'a, C> {
impl<'a, C: Signer + Clone> RequestBuilder<'a, C> {
pub fn from(
program_id: Pubkey,
cluster: &str,

View File

@ -14,6 +14,6 @@
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
"test": "anchor test --skip-lint && anchor clean"
}
}

View File

@ -14,6 +14,6 @@
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
"test": "anchor test --skip-lint && anchor clean"
}
}

View File

@ -14,6 +14,6 @@
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
"test": "anchor test --skip-lint && anchor clean"
}
}

View File

@ -14,6 +14,6 @@
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
"test": "anchor test --skip-lint && anchor clean"
}
}

View File

@ -14,6 +14,6 @@
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
"test": "anchor test --skip-lint && anchor clean"
}
}

View File

@ -1,19 +1,19 @@
{
"name": "basic-5",
"version": "0.29.0",
"license": "(MIT OR Apache-2.0)",
"homepage": "https://github.com/coral-xyz/anchor#readme",
"bugs": {
"url": "https://github.com/coral-xyz/anchor/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/coral-xyz/anchor.git"
},
"engines": {
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint"
}
}
"name": "basic-5",
"version": "0.29.0",
"license": "(MIT OR Apache-2.0)",
"homepage": "https://github.com/coral-xyz/anchor#readme",
"bugs": {
"url": "https://github.com/coral-xyz/anchor/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/coral-xyz/anchor.git"
},
"engines": {
"node": ">=11"
},
"scripts": {
"test": "anchor test --skip-lint && anchor clean"
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "anchor-idl"
version = "0.29.0"
version = "0.1.0"
authors = ["Anchor Maintainers <accounts@200ms.io>"]
repository = "https://github.com/coral-xyz/anchor"
rust-version = "1.60"
@ -13,18 +13,13 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
build = [
"anyhow",
"regex",
"serde",
"serde_json",
]
build = ["anchor-syn", "regex"]
[dependencies]
anchor-syn = { path = "../lang/syn", version = "0.29.0", features = ["idl-types"] }
anyhow = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# `build` feature only
anyhow = { version = "1", optional = true }
anchor-syn = { path = "../lang/syn", version = "0.29.0", optional = true }
regex = { version = "1", optional = true }
serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1", optional = true }

View File

@ -12,6 +12,38 @@ use serde::Deserialize;
use crate::types::{Idl, IdlEvent, IdlTypeDef};
/// A trait that types must implement in order to include the type in the IDL definition.
///
/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize`
/// proc macro. Note that manually implementing the `AnchorSerialize` trait does **NOT** have the
/// same effect.
///
/// Types that don't implement this trait will cause a compile error during the IDL generation.
///
/// The default implementation of the trait allows the program to compile but the type does **NOT**
/// get included in the IDL.
pub trait IdlBuild {
/// Create an IDL type definition for the type.
///
/// The type is only included in the IDL if this method returns `Some`.
fn create_type() -> Option<IdlTypeDef> {
None
}
/// Insert all types that are included in the current type definition to the given map.
fn insert_types(_types: &mut BTreeMap<String, IdlTypeDef>) {}
/// Get the full module path of the type.
///
/// The full path will be used in the case of a conflicting type definition, e.g. when there
/// are multiple structs with the same name.
///
/// The default implementation covers most cases.
fn get_full_path() -> String {
std::any::type_name::<Self>().into()
}
}
/// Generate IDL via compilation.
pub fn build_idl(
program_path: impl AsRef<Path>,
@ -35,19 +67,10 @@ pub fn build_idl(
Ok(idl)
}
// Build IDL.
/// Build IDL.
fn build(program_path: &Path, resolution: bool, no_docs: bool) -> Result<Idl> {
// `nightly` toolchain is currently required for building the IDL.
//
// Pinning the toolchain to an older date in order to fix
// `error[E0635]: unknown feature stdsimd` error from `ahash`.
// See: https://github.com/tkaitchuck/aHash/issues/200
//
// There is also another error when using a date after 2024-01-30
// `error[E0412]: cannot find type `T` in this scope``
//
// TODO: Unpin `nightly` release after upgrading Solana to `1.18`.
const TOOLCHAIN: &str = "+nightly-2024-01-30";
const TOOLCHAIN: &str = "+nightly";
install_toolchain_if_needed(TOOLCHAIN)?;
let output = Command::new("cargo")

View File

@ -4,3 +4,6 @@ pub mod types;
#[cfg(feature = "build")]
pub mod build;
#[cfg(feature = "build")]
pub use serde_json;

View File

@ -1,3 +1,501 @@
//! IDL types are re-exported from [`anchor_syn`].
use std::str::FromStr;
pub use anchor_syn::idl::types::*;
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
/// IDL specification Semantic Version
pub const IDL_SPEC: &str = env!("CARGO_PKG_VERSION");
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Idl {
pub address: String,
pub metadata: IdlMetadata,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
pub instructions: Vec<IdlInstruction>,
#[serde(default, skip_serializing_if = "is_default")]
pub accounts: Vec<IdlAccount>,
#[serde(default, skip_serializing_if = "is_default")]
pub events: Vec<IdlEvent>,
#[serde(default, skip_serializing_if = "is_default")]
pub errors: Vec<IdlErrorCode>,
#[serde(default, skip_serializing_if = "is_default")]
pub types: Vec<IdlTypeDef>,
#[serde(default, skip_serializing_if = "is_default")]
pub constants: Vec<IdlConst>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlMetadata {
pub name: String,
pub version: String,
pub spec: String,
#[serde(skip_serializing_if = "is_default")]
pub description: Option<String>,
#[serde(skip_serializing_if = "is_default")]
pub repository: Option<String>,
#[serde(default, skip_serializing_if = "is_default")]
pub dependencies: Vec<IdlDependency>,
#[serde(skip_serializing_if = "is_default")]
pub contact: Option<String>,
#[serde(skip_serializing_if = "is_default")]
pub deployments: Option<IdlDeployments>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlDependency {
pub name: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlDeployments {
pub mainnet: Option<String>,
pub testnet: Option<String>,
pub devnet: Option<String>,
pub localnet: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlInstruction {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
pub discriminator: IdlDiscriminator,
pub accounts: Vec<IdlInstructionAccountItem>,
pub args: Vec<IdlField>,
#[serde(skip_serializing_if = "is_default")]
pub returns: Option<IdlType>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum IdlInstructionAccountItem {
Composite(IdlInstructionAccounts),
Single(IdlInstructionAccount),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlInstructionAccount {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(default, skip_serializing_if = "is_default")]
pub writable: bool,
#[serde(default, skip_serializing_if = "is_default")]
pub signer: bool,
#[serde(default, skip_serializing_if = "is_default")]
pub optional: bool,
#[serde(skip_serializing_if = "is_default")]
pub address: Option<String>,
#[serde(skip_serializing_if = "is_default")]
pub pda: Option<IdlPda>,
#[serde(default, skip_serializing_if = "is_default")]
pub relations: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlInstructionAccounts {
pub name: String,
pub accounts: Vec<IdlInstructionAccountItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlPda {
pub seeds: Vec<IdlSeed>,
#[serde(skip_serializing_if = "is_default")]
pub program: Option<IdlSeed>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlSeed {
Const(IdlSeedConst),
Arg(IdlSeedArg),
Account(IdlSeedAccount),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlSeedConst {
pub value: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlSeedArg {
pub path: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlSeedAccount {
pub path: String,
#[serde(skip_serializing_if = "is_default")]
pub account: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlAccount {
pub name: String,
pub discriminator: IdlDiscriminator,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlEvent {
pub name: String,
pub discriminator: IdlDiscriminator,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlConst {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(rename = "type")]
pub ty: IdlType,
pub value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct IdlErrorCode {
pub code: u32,
pub name: String,
#[serde(skip_serializing_if = "is_default")]
pub msg: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlField {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(rename = "type")]
pub ty: IdlType,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlTypeDef {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(default, skip_serializing_if = "is_default")]
pub serialization: IdlSerialization,
#[serde(skip_serializing_if = "is_default")]
pub repr: Option<IdlRepr>,
#[serde(default, skip_serializing_if = "is_default")]
pub generics: Vec<IdlTypeDefGeneric>,
#[serde(rename = "type")]
pub ty: IdlTypeDefTy,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum IdlSerialization {
#[default]
Borsh,
Bytemuck,
BytemuckUnsafe,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
#[non_exhaustive]
pub enum IdlRepr {
Rust(IdlReprModifier),
C(IdlReprModifier),
Transparent,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlReprModifier {
#[serde(default, skip_serializing_if = "is_default")]
pub packed: bool,
#[serde(skip_serializing_if = "is_default")]
pub align: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlTypeDefGeneric {
Type {
name: String,
},
Const {
name: String,
#[serde(rename = "type")]
ty: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlTypeDefTy {
Struct {
#[serde(skip_serializing_if = "is_default")]
fields: Option<IdlDefinedFields>,
},
Enum {
variants: Vec<IdlEnumVariant>,
},
Type {
alias: IdlType,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlEnumVariant {
pub name: String,
#[serde(skip_serializing_if = "is_default")]
pub fields: Option<IdlDefinedFields>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum IdlDefinedFields {
Named(Vec<IdlField>),
Tuple(Vec<IdlType>),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum IdlArrayLen {
Generic(String),
#[serde(untagged)]
Value(usize),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlGenericArg {
Type {
#[serde(rename = "type")]
ty: IdlType,
},
Const {
value: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum IdlType {
Bool,
U8,
I8,
U16,
I16,
U32,
I32,
F32,
U64,
I64,
F64,
U128,
I128,
U256,
I256,
Bytes,
String,
Pubkey,
Option(Box<IdlType>),
Vec(Box<IdlType>),
Array(Box<IdlType>, IdlArrayLen),
Defined {
name: String,
#[serde(default, skip_serializing_if = "is_default")]
generics: Vec<IdlGenericArg>,
},
Generic(String),
}
impl FromStr for IdlType {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut s = s.to_owned();
s.retain(|c| !c.is_whitespace());
let r = match s.as_str() {
"bool" => IdlType::Bool,
"u8" => IdlType::U8,
"i8" => IdlType::I8,
"u16" => IdlType::U16,
"i16" => IdlType::I16,
"u32" => IdlType::U32,
"i32" => IdlType::I32,
"f32" => IdlType::F32,
"u64" => IdlType::U64,
"i64" => IdlType::I64,
"f64" => IdlType::F64,
"u128" => IdlType::U128,
"i128" => IdlType::I128,
"u256" => IdlType::U256,
"i256" => IdlType::I256,
"Vec<u8>" => IdlType::Bytes,
"String" | "&str" | "&'staticstr" => IdlType::String,
"Pubkey" => IdlType::Pubkey,
_ => {
if let Some(inner) = s.strip_prefix("Option<") {
let inner_ty = Self::from_str(
inner
.strip_suffix('>')
.ok_or_else(|| anyhow!("Invalid Option"))?,
)?;
return Ok(IdlType::Option(Box::new(inner_ty)));
}
if let Some(inner) = s.strip_prefix("Vec<") {
let inner_ty = Self::from_str(
inner
.strip_suffix('>')
.ok_or_else(|| anyhow!("Invalid Vec"))?,
)?;
return Ok(IdlType::Vec(Box::new(inner_ty)));
}
if s.starts_with('[') {
fn array_from_str(inner: &str) -> IdlType {
match inner.strip_suffix(']') {
Some(nested_inner) => array_from_str(&nested_inner[1..]),
None => {
let (raw_type, raw_length) = inner.rsplit_once(';').unwrap();
let ty = IdlType::from_str(raw_type).unwrap();
let len = match raw_length.replace('_', "").parse::<usize>() {
Ok(len) => IdlArrayLen::Value(len),
Err(_) => IdlArrayLen::Generic(raw_length.to_owned()),
};
IdlType::Array(Box::new(ty), len)
}
}
}
return Ok(array_from_str(&s));
}
// Defined
let (name, generics) = if let Some(i) = s.find('<') {
(
s.get(..i).unwrap().to_owned(),
s.get(i + 1..)
.unwrap()
.strip_suffix('>')
.unwrap()
.split(',')
.map(|g| g.trim().to_owned())
.map(|g| {
if g.parse::<bool>().is_ok()
|| g.parse::<u128>().is_ok()
|| g.parse::<i128>().is_ok()
|| g.parse::<char>().is_ok()
{
Ok(IdlGenericArg::Const { value: g })
} else {
Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty })
}
})
.collect::<Result<Vec<_>, _>>()?,
)
} else {
(s.to_owned(), vec![])
};
IdlType::Defined { name, generics }
}
};
Ok(r)
}
}
pub type IdlDiscriminator = Vec<u8>;
/// Get whether the given data is the default of its type.
fn is_default<T: Default + PartialEq>(it: &T) -> bool {
*it == T::default()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn option() {
assert_eq!(
IdlType::from_str("Option<bool>").unwrap(),
IdlType::Option(Box::new(IdlType::Bool))
)
}
#[test]
fn vector() {
assert_eq!(
IdlType::from_str("Vec<bool>").unwrap(),
IdlType::Vec(Box::new(IdlType::Bool))
)
}
#[test]
fn array() {
assert_eq!(
IdlType::from_str("[Pubkey; 16]").unwrap(),
IdlType::Array(Box::new(IdlType::Pubkey), IdlArrayLen::Value(16))
);
}
#[test]
fn array_with_underscored_length() {
assert_eq!(
IdlType::from_str("[u8; 50_000]").unwrap(),
IdlType::Array(Box::new(IdlType::U8), IdlArrayLen::Value(50000))
);
}
#[test]
fn multidimensional_array() {
assert_eq!(
IdlType::from_str("[[u8; 16]; 32]").unwrap(),
IdlType::Array(
Box::new(IdlType::Array(
Box::new(IdlType::U8),
IdlArrayLen::Value(16)
)),
IdlArrayLen::Value(32)
)
);
}
#[test]
fn generic_array() {
assert_eq!(
IdlType::from_str("[u64; T]").unwrap(),
IdlType::Array(Box::new(IdlType::U64), IdlArrayLen::Generic("T".into()))
);
}
#[test]
fn defined() {
assert_eq!(
IdlType::from_str("MyStruct").unwrap(),
IdlType::Defined {
name: "MyStruct".into(),
generics: vec![]
}
)
}
#[test]
fn defined_with_generics() {
assert_eq!(
IdlType::from_str("MyStruct<Pubkey, u64, 8>").unwrap(),
IdlType::Defined {
name: "MyStruct".into(),
generics: vec![
IdlGenericArg::Type {
ty: IdlType::Pubkey
},
IdlGenericArg::Type { ty: IdlType::U64 },
IdlGenericArg::Const { value: "8".into() },
],
}
)
}
}

View File

@ -33,7 +33,7 @@ idl-build = [
"anchor-attribute-program/idl-build",
"anchor-derive-accounts/idl-build",
"anchor-derive-serde/idl-build",
"anchor-syn/idl-build",
"anchor-idl/build",
]
init-if-needed = ["anchor-derive-accounts/init-if-needed"]
interface-instructions = ["anchor-attribute-program/interface-instructions"]
@ -49,8 +49,8 @@ anchor-derive-accounts = { path = "./derive/accounts", version = "0.29.0" }
anchor-derive-serde = { path = "./derive/serde", version = "0.29.0" }
anchor-derive-space = { path = "./derive/space", version = "0.29.0" }
# `anchor-syn` should only be included with `idl-build` feature
anchor-syn = { path = "./syn", version = "0.29.0", optional = true }
# `anchor-idl` should only be included with `idl-build` feature
anchor-idl = { path = "../idl", version = "0.1.0", optional = true }
arrayref = "0.3"
base64 = "0.21"
@ -59,6 +59,5 @@ borsh = ">=0.9, <0.11"
bytemuck = "1"
solana-program = "1.16"
thiserror = "1"
# TODO: Remove. This crate has been added to fix a build error with the 1.16.0 release.
getrandom = { version = "0.2", features = ["custom"] }
getrandom = { version = "0.2", features = ["custom"] }

View File

@ -10,7 +10,6 @@ extern crate proc_macro;
use proc_macro2::{Delimiter, Span, TokenTree};
use quote::{quote, ToTokens};
use std::convert::TryFrom;
use syn::{
bracketed,
parse::{Parse, ParseStream, Result},

View File

@ -413,7 +413,7 @@ pub fn zero_copy(
#ret
})
.unwrap();
let idl_build_impl = anchor_syn::idl::build::impl_idl_build_struct(&zc_struct);
let idl_build_impl = anchor_syn::idl::impl_idl_build_struct(&zc_struct);
return proc_macro::TokenStream::from(quote! {
#ret
#idl_build_impl
@ -436,7 +436,7 @@ pub fn declare_id(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
#[cfg(feature = "idl-build")]
{
let idl_print = anchor_syn::idl::build::gen_idl_print_fn_address(address);
let idl_print = anchor_syn::idl::gen_idl_print_fn_address(address);
return proc_macro::TokenStream::from(quote! {
#ret
#idl_print

View File

@ -13,7 +13,7 @@ pub fn constant(
let ts = match syn::parse(input).unwrap() {
syn::Item::Const(item) => {
let idl_print = anchor_syn::idl::build::gen_idl_print_fn_constant(&item);
let idl_print = anchor_syn::idl::gen_idl_print_fn_constant(&item);
quote! {
#item
#idl_print

View File

@ -46,7 +46,7 @@ pub fn event(
#[cfg(feature = "idl-build")]
{
let idl_build = anchor_syn::idl::build::gen_idl_print_fn_event(&event_strct);
let idl_build = anchor_syn::idl::gen_idl_print_fn_event(&event_strct);
return proc_macro::TokenStream::from(quote! {
#ret
#idl_build

View File

@ -17,7 +17,8 @@ idl-build = ["anchor-syn/idl-build"]
interface-instructions = ["anchor-syn/interface-instructions"]
[dependencies]
anchor-syn = { path = "../../syn", version = "0.29.0", features = ["idl-types"] }
anchor-idl = { path = "../../../idl", version = "0.1.0" }
anchor-syn = { path = "../../syn", version = "0.29.0" }
anyhow = "1"
bs58 = "0.5"
heck = "0.3"

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::{
use anchor_idl::types::{
Idl, IdlArrayLen, IdlDefinedFields, IdlField, IdlGenericArg, IdlRepr, IdlSerialization,
IdlType, IdlTypeDef, IdlTypeDefGeneric, IdlTypeDefTy,
};
@ -88,6 +88,7 @@ pub fn convert_idl_type_to_str(ty: &IdlType) -> String {
.map(|generics| format!("{name}<{generics}>"))
.unwrap_or(name.into()),
IdlType::Generic(ty) => ty.into(),
_ => unimplemented!("{ty:?}"),
}
}
@ -151,6 +152,7 @@ pub fn convert_idl_type_def_to_ts(
IdlRepr::Rust(_) => "Rust",
IdlRepr::C(_) => "C",
IdlRepr::Transparent => "transparent",
_ => unimplemented!("{repr:?}"),
};
let kind = format_ident!("{kind}");

View File

@ -1,7 +1,7 @@
mod common;
mod mods;
use anchor_syn::idl::types::Idl;
use anchor_idl::types::Idl;
use anyhow::anyhow;
use quote::{quote, ToTokens};
use syn::parse::{Parse, ParseStream};
@ -10,7 +10,7 @@ use common::gen_docs;
use mods::{
accounts::gen_accounts_mod, client::gen_client_mod, constants::gen_constants_mod,
cpi::gen_cpi_mod, events::gen_events_mod, internal::gen_internal_mod, program::gen_program_mod,
types::gen_types_mod,
types::gen_types_mod, utils::gen_utils_mod,
};
pub struct DeclareProgram {
@ -66,6 +66,9 @@ fn gen_program(idl: &Idl, name: &syn::Ident) -> proc_macro2::TokenStream {
let client_mod = gen_client_mod(idl);
let internal_mod = gen_internal_mod(idl);
// Utils
let utils_mod = gen_utils_mod(idl);
quote! {
#docs
pub mod #name {
@ -82,6 +85,8 @@ fn gen_program(idl: &Idl, name: &syn::Ident) -> proc_macro2::TokenStream {
#cpi_mod
#client_mod
#internal_mod
#utils_mod
}
}
}

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::{Idl, IdlSerialization};
use anchor_idl::types::{Idl, IdlSerialization};
use quote::{format_ident, quote};
use super::common::{convert_idl_type_def_to_ts, gen_discriminator, get_canonical_program_id};

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::Idl;
use anchor_idl::types::Idl;
use quote::quote;
use super::common::gen_accounts_common;

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::{Idl, IdlType};
use anchor_idl::types::{Idl, IdlType};
use quote::{format_ident, quote, ToTokens};
use super::common::convert_idl_type_to_str;

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::Idl;
use anchor_idl::types::Idl;
use heck::CamelCase;
use quote::{format_ident, quote};

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::Idl;
use anchor_idl::types::Idl;
use quote::{format_ident, quote};
use super::common::{convert_idl_type_def_to_ts, gen_discriminator};

View File

@ -1,6 +1,6 @@
use anchor_idl::types::{Idl, IdlInstructionAccountItem};
use anchor_syn::{
codegen::accounts::{__client_accounts, __cpi_client_accounts},
idl::types::{Idl, IdlInstructionAccountItem},
parser::accounts,
AccountsStruct,
};
@ -145,7 +145,19 @@ fn gen_internal_accounts_common(
pub #name: #acc_expr
}
}
IdlInstructionAccountItem::Composite(_accs) => todo!("Composite"),
IdlInstructionAccountItem::Composite(accs) => {
let name = format_ident!("{}", accs.name);
let ty_name = idl
.instructions
.iter()
.find(|ix| ix.accounts == accs.accounts)
.map(|ix| format_ident!("{}", ix.name.to_camel_case()))
.expect("Instruction must exist");
quote! {
pub #name: #ty_name #generics
}
}
});
quote! {

View File

@ -6,5 +6,6 @@ pub mod events;
pub mod internal;
pub mod program;
pub mod types;
pub mod utils;
use super::common;

View File

@ -1,4 +1,4 @@
use anchor_syn::idl::types::Idl;
use anchor_idl::types::Idl;
use quote::quote;
use super::common::convert_idl_type_def_to_ts;

View File

@ -0,0 +1,69 @@
use anchor_idl::types::Idl;
use quote::{format_ident, quote};
use super::common::gen_discriminator;
pub fn gen_utils_mod(idl: &Idl) -> proc_macro2::TokenStream {
let event = gen_event(idl);
quote! {
/// Program utilities.
pub mod utils {
#event
}
}
}
fn gen_event(idl: &Idl) -> proc_macro2::TokenStream {
let variants = idl
.events
.iter()
.map(|ev| format_ident!("{}", ev.name))
.map(|name| quote! { #name(#name) });
let match_arms = idl.events.iter().map(|ev| {
let disc = gen_discriminator(&ev.discriminator);
let name = format_ident!("{}", ev.name);
let event = quote! {
#name::try_from_slice(&value[8..])
.map(Self::#name)
.map_err(Into::into)
};
quote! { #disc => #event }
});
quote! {
use super::{*, events::*};
/// An enum that includes all events of the declared program as a tuple variant.
///
/// See [`Self::try_from_bytes`] to create an instance from bytes.
pub enum Event {
#(#variants,)*
}
impl Event {
/// Try to create an event based on the given bytes.
///
/// This method returns an error if the discriminator of the given bytes don't match
/// with any of the existing events, or if the deserialization fails.
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
Self::try_from(bytes)
}
}
impl TryFrom<&[u8]> for Event {
type Error = anchor_lang::error::Error;
fn try_from(value: &[u8]) -> Result<Self> {
if value.len() < 8 {
return Err(ProgramError::InvalidArgument.into());
}
match &value[..8] {
#(#match_arms,)*
_ => Err(ProgramError::InvalidArgument.into()),
}
}
}
}
}

View File

@ -32,7 +32,7 @@ pub fn anchor_serialize(input: TokenStream) -> TokenStream {
#[cfg(feature = "idl-build")]
{
use anchor_syn::idl::build::*;
use anchor_syn::idl::*;
use quote::quote;
let idl_build_impl = match syn::parse(input).unwrap() {

View File

@ -9,7 +9,6 @@ use solana_program::bpf_loader_upgradeable::{self, UpgradeableLoaderState};
use solana_program::instruction::AccountMeta;
use solana_program::pubkey::Pubkey;
use std::collections::BTreeSet;
use std::convert::TryFrom;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;

View File

@ -2,11 +2,7 @@
use crate::error::ErrorCode;
use crate::*;
use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::pubkey::Pubkey;
use solana_program::system_program;
use std::collections::BTreeSet;
use std::ops::Deref;
/// Type validating that the account is owned by the system program

View File

@ -126,6 +126,56 @@ pub enum ErrorCode {
/// 2023 - A mint token program constraint was violated
#[msg("An associated token account token program constraint was violated")]
ConstraintAssociatedTokenTokenProgram,
/// Extension constraints
///
/// 2024 - A group pointer extension constraint was violated
#[msg("A group pointer extension constraint was violated")]
ConstraintMintGroupPointerExtension,
/// 2025 - A group pointer extension authority constraint was violated
#[msg("A group pointer extension authority constraint was violated")]
ConstraintMintGroupPointerExtensionAuthority,
/// 2026 - A group pointer extension group address constraint was violated
#[msg("A group pointer extension group address constraint was violated")]
ConstraintMintGroupPointerExtensionGroupAddress,
/// 2027 - A group member pointer extension constraint was violated
#[msg("A group member pointer extension constraint was violated")]
ConstraintMintGroupMemberPointerExtension,
/// 2028 - A group member pointer extension authority constraint was violated
#[msg("A group member pointer extension authority constraint was violated")]
ConstraintMintGroupMemberPointerExtensionAuthority,
/// 2029 - A group member pointer extension member address constraint was violated
#[msg("A group member pointer extension group address constraint was violated")]
ConstraintMintGroupMemberPointerExtensionMemberAddress,
/// 2030 - A metadata pointer extension constraint was violated
#[msg("A metadata pointer extension constraint was violated")]
ConstraintMintMetadataPointerExtension,
/// 2031 - A metadata pointer extension authority constraint was violated
#[msg("A metadata pointer extension authority constraint was violated")]
ConstraintMintMetadataPointerExtensionAuthority,
/// 2032 - A metadata pointer extension metadata address constraint was violated
#[msg("A metadata pointer extension metadata address constraint was violated")]
ConstraintMintMetadataPointerExtensionMetadataAddress,
/// 2033 - A close authority extension constraint was violated
#[msg("A close authority constraint was violated")]
ConstraintMintCloseAuthorityExtension,
/// 2034 - A close authority extension authority constraint was violated
#[msg("A close authority extension authority constraint was violated")]
ConstraintMintCloseAuthorityExtensionAuthority,
/// 2035 - A permanent delegate extension constraint was violated
#[msg("A permanent delegate extension constraint was violated")]
ConstraintMintPermanentDelegateExtension,
/// 2036 - A permanent delegate extension authority constraint was violated
#[msg("A permanent delegate extension delegate constraint was violated")]
ConstraintMintPermanentDelegateExtensionDelegate,
/// 2037 - A transfer hook extension constraint was violated
#[msg("A transfer hook extension constraint was violated")]
ConstraintMintTransferHookExtension,
/// 2038 - A transfer hook extension authority constraint was violated
#[msg("A transfer hook extension authority constraint was violated")]
ConstraintMintTransferHookExtensionAuthority,
/// 2039 - A transfer hook extension transfer hook program id constraint was violated
#[msg("A transfer hook extension transfer hook program id constraint was violated")]
ConstraintMintTransferHookExtensionProgramId,
// Require
/// 2500 - A require expression was violated

View File

@ -18,7 +18,6 @@
//! Anchor programs. To remove them, one can use the `no-idl` feature.
use crate::prelude::*;
use solana_program::pubkey::Pubkey;
// The first 8 bytes of an instruction to create or modify the IDL account. This
// instruction is defined outside the main program's instruction enum, so that
@ -79,3 +78,6 @@ impl IdlAccount {
"anchor:idl"
}
}
#[cfg(feature = "idl-build")]
pub use anchor_idl::{build::IdlBuild, *};

View File

@ -65,7 +65,7 @@ pub use solana_program;
pub use anchor_attribute_event::{emit_cpi, event_cpi};
#[cfg(feature = "idl-build")]
pub use anchor_syn::{self, idl::build::IdlBuild};
pub use idl::IdlBuild;
#[cfg(feature = "interface-instructions")]
pub use anchor_attribute_program::interface;
@ -423,7 +423,7 @@ pub mod prelude {
pub use super::{emit_cpi, event_cpi};
#[cfg(feature = "idl-build")]
pub use super::IdlBuild;
pub use super::idl::IdlBuild;
#[cfg(feature = "interface-instructions")]
pub use super::interface;

View File

@ -17,8 +17,7 @@ allow-missing-optionals = []
anchor-debug = []
event-cpi = []
hash = []
idl-build = ["idl-types", "cargo_toml"]
idl-types = []
idl-build = ["cargo_toml"]
init-if-needed = []
interface-instructions = []

View File

@ -1,6 +1,5 @@
use quote::quote;
use std::collections::HashSet;
use syn::Expr;
use crate::*;
@ -662,6 +661,16 @@ fn generate_constraint_init_group(
decimals,
freeze_authority,
token_program,
group_pointer_authority,
group_pointer_group_address,
group_member_pointer_authority,
group_member_pointer_member_address,
metadata_pointer_authority,
metadata_pointer_metadata_address,
close_authority,
permanent_delegate,
transfer_hook_authority,
transfer_hook_program_id,
} => {
let token_program = match token_program {
Some(t) => t.to_token_stream(),
@ -673,6 +682,59 @@ fn generate_constraint_init_group(
None => quote! {},
};
// extension checks
let group_pointer_authority_check = match group_pointer_authority {
Some(gpa) => check_scope.generate_check(gpa),
None => quote! {},
};
let group_pointer_group_address_check = match group_pointer_group_address {
Some(gpga) => check_scope.generate_check(gpga),
None => quote! {},
};
let group_member_pointer_authority_check = match group_member_pointer_authority {
Some(gmpa) => check_scope.generate_check(gmpa),
None => quote! {},
};
let group_member_pointer_member_address_check =
match group_member_pointer_member_address {
Some(gmpm) => check_scope.generate_check(gmpm),
None => quote! {},
};
let metadata_pointer_authority_check = match metadata_pointer_authority {
Some(mpa) => check_scope.generate_check(mpa),
None => quote! {},
};
let metadata_pointer_metadata_address_check = match metadata_pointer_metadata_address {
Some(mpma) => check_scope.generate_check(mpma),
None => quote! {},
};
let close_authority_check = match close_authority {
Some(ca) => check_scope.generate_check(ca),
None => quote! {},
};
let transfer_hook_authority_check = match transfer_hook_authority {
Some(tha) => check_scope.generate_check(tha),
None => quote! {},
};
let transfer_hook_program_id_check = match transfer_hook_program_id {
Some(thpid) => check_scope.generate_check(thpid),
None => quote! {},
};
let permanent_delegate_check = match permanent_delegate {
Some(pd) => check_scope.generate_check(pd),
None => quote! {},
};
let system_program_optional_check = check_scope.generate_check(system_program);
let token_program_optional_check = check_scope.generate_check(&token_program);
let rent_optional_check = check_scope.generate_check(rent);
@ -683,23 +745,126 @@ fn generate_constraint_init_group(
#rent_optional_check
#owner_optional_check
#freeze_authority_optional_check
#group_pointer_authority_check
#group_pointer_group_address_check
#group_member_pointer_authority_check
#group_member_pointer_member_address_check
#metadata_pointer_authority_check
#metadata_pointer_metadata_address_check
#close_authority_check
#transfer_hook_authority_check
#transfer_hook_program_id_check
#permanent_delegate_check
};
let payer_optional_check = check_scope.generate_check(payer);
let create_account = generate_create_account(
field,
quote! {::anchor_spl::token::Mint::LEN},
quote! {&#token_program.key()},
quote! {#payer},
seeds_with_bump,
);
let mut extensions = vec![];
if group_pointer_authority.is_some() || group_pointer_group_address.is_some() {
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupPointer});
}
if group_member_pointer_authority.is_some()
|| group_member_pointer_member_address.is_some()
{
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupMemberPointer});
}
if metadata_pointer_authority.is_some() || metadata_pointer_metadata_address.is_some() {
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MetadataPointer});
}
if close_authority.is_some() {
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MintCloseAuthority});
}
if transfer_hook_authority.is_some() || transfer_hook_program_id.is_some() {
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::TransferHook});
}
if permanent_delegate.is_some() {
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::PermanentDelegate});
}
let mint_space = if extensions.is_empty() {
quote! { ::anchor_spl::token::Mint::LEN }
} else {
quote! { ::anchor_spl::token_interface::find_mint_account_size(Some(&vec![#(#extensions),*]))? }
};
let extensions = if extensions.is_empty() {
quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::None}
} else {
quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::Some(&vec![#(#extensions),*])}
};
let freeze_authority = match freeze_authority {
Some(fa) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#fa.key()) },
None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
};
let group_pointer_authority = match group_pointer_authority {
Some(gpa) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#gpa.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let group_pointer_group_address = match group_pointer_group_address {
Some(gpga) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#gpga.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let group_member_pointer_authority = match group_member_pointer_authority {
Some(gmpa) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#gmpa.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let group_member_pointer_member_address = match group_member_pointer_member_address {
Some(gmpma) => {
quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#gmpma.key()) }
}
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let metadata_pointer_authority = match metadata_pointer_authority {
Some(mpa) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#mpa.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let metadata_pointer_metadata_address = match metadata_pointer_metadata_address {
Some(mpma) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#mpma.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let close_authority = match close_authority {
Some(ca) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#ca.key()) },
None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
};
let permanent_delegate = match permanent_delegate {
Some(pd) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#pd.key()) },
None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
};
let transfer_hook_authority = match transfer_hook_authority {
Some(tha) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#tha.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let transfer_hook_program_id = match transfer_hook_program_id {
Some(thpid) => {
quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#thpid.key()) }
}
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};
let create_account = generate_create_account(
field,
mint_space,
quote! {&#token_program.key()},
quote! {#payer},
seeds_with_bump,
);
quote! {
// Define the bump and pda variable.
#find_pda
@ -716,6 +881,78 @@ fn generate_constraint_init_group(
// Create the account with the system program.
#create_account
// Initialize extensions.
if let Some(extensions) = #extensions {
for e in extensions {
match e {
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupPointer => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::GroupPointerInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::group_pointer_initialize(cpi_ctx, #group_pointer_authority, #group_pointer_group_address)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupMemberPointer => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::GroupMemberPointerInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::group_member_pointer_initialize(cpi_ctx, #group_member_pointer_authority, #group_member_pointer_member_address)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MetadataPointer => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::MetadataPointerInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::metadata_pointer_initialize(cpi_ctx, #metadata_pointer_authority, #metadata_pointer_metadata_address)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MintCloseAuthority => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::MintCloseAuthorityInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::mint_close_authority_initialize(cpi_ctx, #close_authority)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::TransferHook => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::TransferHookInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::transfer_hook_initialize(cpi_ctx, #transfer_hook_authority, #transfer_hook_program_id)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::NonTransferable => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::NonTransferableMintInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::non_transferable_mint_initialize(cpi_ctx)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::PermanentDelegate => {
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::PermanentDelegateInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
};
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::permanent_delegate_initialize(cpi_ctx, #permanent_delegate.unwrap())?;
},
_ => {} // do nothing
}
};
}
// Initialize the mint account.
let cpi_program = #token_program.to_account_info();
let accounts = ::anchor_spl::token_interface::InitializeMint2 {
@ -724,6 +961,7 @@ fn generate_constraint_init_group(
let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
::anchor_spl::token_interface::initialize_mint2(cpi_ctx, #decimals, &#owner.key(), #freeze_authority)?;
}
let pa: #ty_decl = #from_account_info_unchecked;
if #if_needed {
if pa.mint_authority != anchor_lang::solana_program::program_option::COption::Some(#owner.key()) {
@ -1069,12 +1307,203 @@ fn generate_constraint_mint(
}
None => quote! {},
};
let group_pointer_authority_check = match &c.group_pointer_authority {
Some(group_pointer_authority) => {
let group_pointer_authority_optional_check =
optional_check_scope.generate_check(group_pointer_authority);
quote! {
let group_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_pointer::GroupPointer>(#account_ref);
if group_pointer.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtension.into());
}
#group_pointer_authority_optional_check
if group_pointer.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_pointer_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtensionAuthority.into());
}
}
}
None => quote! {},
};
let group_pointer_group_address_check = match &c.group_pointer_group_address {
Some(group_pointer_group_address) => {
let group_pointer_group_address_optional_check =
optional_check_scope.generate_check(group_pointer_group_address);
quote! {
let group_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_pointer::GroupPointer>(#account_ref);
if group_pointer.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtension.into());
}
#group_pointer_group_address_optional_check
if group_pointer.unwrap().group_address != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_pointer_group_address.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtensionGroupAddress.into());
}
}
}
None => quote! {},
};
let group_member_pointer_authority_check = match &c.group_member_pointer_authority {
Some(group_member_pointer_authority) => {
let group_member_pointer_authority_optional_check =
optional_check_scope.generate_check(group_member_pointer_authority);
quote! {
let group_member_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_member_pointer::GroupMemberPointer>(#account_ref);
if group_member_pointer.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtension.into());
}
#group_member_pointer_authority_optional_check
if group_member_pointer.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_member_pointer_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtensionAuthority.into());
}
}
}
None => quote! {},
};
let group_member_pointer_member_address_check = match &c.group_member_pointer_member_address {
Some(group_member_pointer_member_address) => {
let group_member_pointer_member_address_optional_check =
optional_check_scope.generate_check(group_member_pointer_member_address);
quote! {
let group_member_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_member_pointer::GroupMemberPointer>(#account_ref);
if group_member_pointer.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtension.into());
}
#group_member_pointer_member_address_optional_check
if group_member_pointer.unwrap().member_address != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_member_pointer_member_address.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtensionMemberAddress.into());
}
}
}
None => quote! {},
};
let metadata_pointer_authority_check = match &c.metadata_pointer_authority {
Some(metadata_pointer_authority) => {
let metadata_pointer_authority_optional_check =
optional_check_scope.generate_check(metadata_pointer_authority);
quote! {
let metadata_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::metadata_pointer::MetadataPointer>(#account_ref);
if metadata_pointer.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtension.into());
}
#metadata_pointer_authority_optional_check
if metadata_pointer.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#metadata_pointer_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtensionAuthority.into());
}
}
}
None => quote! {},
};
let metadata_pointer_metadata_address_check = match &c.metadata_pointer_metadata_address {
Some(metadata_pointer_metadata_address) => {
let metadata_pointer_metadata_address_optional_check =
optional_check_scope.generate_check(metadata_pointer_metadata_address);
quote! {
let metadata_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::metadata_pointer::MetadataPointer>(#account_ref);
if metadata_pointer.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtension.into());
}
#metadata_pointer_metadata_address_optional_check
if metadata_pointer.unwrap().metadata_address != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#metadata_pointer_metadata_address.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtensionMetadataAddress.into());
}
}
}
None => quote! {},
};
let close_authority_check = match &c.close_authority {
Some(close_authority) => {
let close_authority_optional_check =
optional_check_scope.generate_check(close_authority);
quote! {
let close_authority = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::mint_close_authority::MintCloseAuthority>(#account_ref);
if close_authority.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintCloseAuthorityExtension.into());
}
#close_authority_optional_check
if close_authority.unwrap().close_authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#close_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintCloseAuthorityExtensionAuthority.into());
}
}
}
None => quote! {},
};
let permanent_delegate_check = match &c.permanent_delegate {
Some(permanent_delegate) => {
let permanent_delegate_optional_check =
optional_check_scope.generate_check(permanent_delegate);
quote! {
let permanent_delegate = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::permanent_delegate::PermanentDelegate>(#account_ref);
if permanent_delegate.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintPermanentDelegateExtension.into());
}
#permanent_delegate_optional_check
if permanent_delegate.unwrap().delegate != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#permanent_delegate.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintPermanentDelegateExtensionDelegate.into());
}
}
}
None => quote! {},
};
let transfer_hook_authority_check = match &c.transfer_hook_authority {
Some(transfer_hook_authority) => {
let transfer_hook_authority_optional_check =
optional_check_scope.generate_check(transfer_hook_authority);
quote! {
let transfer_hook = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::transfer_hook::TransferHook>(#account_ref);
if transfer_hook.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtension.into());
}
#transfer_hook_authority_optional_check
if transfer_hook.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#transfer_hook_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtensionAuthority.into());
}
}
}
None => quote! {},
};
let transfer_hook_program_id_check = match &c.transfer_hook_program_id {
Some(transfer_hook_program_id) => {
let transfer_hook_program_id_optional_check =
optional_check_scope.generate_check(transfer_hook_program_id);
quote! {
let transfer_hook = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::transfer_hook::TransferHook>(#account_ref);
if transfer_hook.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtension.into());
}
#transfer_hook_program_id_optional_check
if transfer_hook.unwrap().program_id != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#transfer_hook_program_id.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtensionProgramId.into());
}
}
}
None => quote! {},
};
quote! {
{
#decimal_check
#mint_authority_check
#freeze_authority_check
#token_program_check
#group_pointer_authority_check
#group_pointer_group_address_check
#group_member_pointer_authority_check
#group_member_pointer_member_address_check
#metadata_pointer_authority_check
#metadata_pointer_metadata_address_check
#close_authority_check
#permanent_delegate_check
#transfer_hook_authority_check
#transfer_hook_program_id_check
}
}
}

View File

@ -37,7 +37,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
#[cfg(feature = "idl-build")]
{
let idl_build_impl = crate::idl::build::gen_idl_build_impl_accounts_struct(accs);
let idl_build_impl = crate::idl::gen_idl_build_impl_accounts_struct(accs);
return quote! {
#ret
#idl_build_impl

View File

@ -100,7 +100,7 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream {
#[cfg(feature = "idl-build")]
{
let idl_print = crate::idl::build::gen_idl_print_fn_error(&error);
let idl_print = crate::idl::gen_idl_print_fn_error(&error);
return quote! {
#ret
#idl_print

View File

@ -39,7 +39,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
#[cfg(feature = "idl-build")]
{
let idl_build_impl = crate::idl::build::gen_idl_print_fn_program(program);
let idl_build_impl = crate::idl::gen_idl_print_fn_program(program);
return quote! {
#ret
#idl_build_impl

View File

@ -3,7 +3,7 @@
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::{convert::TryFrom, fmt, mem, str::FromStr};
use std::{fmt, mem, str::FromStr};
use thiserror::Error;
pub const HASH_BYTES: usize = 32;

View File

@ -1,21 +0,0 @@
#![allow(dead_code)]
mod accounts;
mod address;
mod common;
mod constant;
mod defined;
mod error;
mod event;
mod external;
mod program;
pub use accounts::gen_idl_build_impl_accounts_struct;
pub use address::gen_idl_print_fn_address;
pub use constant::gen_idl_print_fn_constant;
pub use defined::{impl_idl_build_enum, impl_idl_build_struct, impl_idl_build_union, IdlBuild};
pub use error::gen_idl_print_fn_error;
pub use event::gen_idl_print_fn_event;
pub use program::gen_idl_print_fn_program;
pub use serde_json;

View File

@ -26,11 +26,11 @@ pub fn get_no_docs() -> bool {
}
pub fn get_idl_module_path() -> TokenStream {
quote!(anchor_lang::anchor_syn::idl::types)
quote!(anchor_lang::idl::types)
}
pub fn get_serde_json_module_path() -> TokenStream {
quote!(anchor_lang::anchor_syn::idl::build::serde_json)
quote!(anchor_lang::idl::serde_json)
}
pub fn gen_print_section(name: &str, value: impl ToTokens) -> TokenStream {

View File

@ -3,23 +3,31 @@ use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use super::{
common::{gen_print_section, get_idl_module_path},
common::{gen_print_section, get_idl_module_path, get_no_docs},
defined::gen_idl_type,
};
use crate::parser::docs;
pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream {
let idl = get_idl_module_path();
let no_docs = get_no_docs();
let name = item.ident.to_string();
let expr = &item.expr;
let fn_name = format_ident!("__anchor_private_print_idl_const_{}", name.to_snake_case());
let docs = match docs::parse(&item.attrs) {
Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
_ => quote! { vec![] },
};
let fn_body = match gen_idl_type(&item.ty, &[]) {
Ok((ty, _)) => gen_print_section(
"const",
quote! {
#idl::IdlConst {
name: #name.into(),
docs: #docs,
ty: #ty,
value: format!("{:?}", #expr),
}

View File

@ -1,55 +1,21 @@
use std::collections::BTreeMap;
use anyhow::{anyhow, Result};
use proc_macro2::TokenStream;
use quote::quote;
use super::common::{get_idl_module_path, get_no_docs};
use crate::{idl::types::IdlTypeDef, parser::docs};
use crate::parser::docs;
/// A trait that types must implement in order to include the type in the IDL definition.
///
/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize`
/// proc macro. Note that manually implementing the `AnchorSerialize` trait does **NOT** have the
/// same effect.
///
/// Types that don't implement this trait will cause a compile error during the IDL generation.
///
/// The default implementation of the trait allows the program to compile but the type does **NOT**
/// get included in the IDL.
pub trait IdlBuild {
/// Create an IDL type definition for the type.
///
/// The type is only included in the IDL if this method returns `Some`.
fn create_type() -> Option<IdlTypeDef> {
None
}
/// Insert all types that are included in the current type definition to the given map.
fn insert_types(_types: &mut BTreeMap<String, IdlTypeDef>) {}
/// Get the full module path of the type.
///
/// The full path will be used in the case of a conflicting type definition, e.g. when there
/// are multiple structs with the same name.
///
/// The default implementation covers most cases.
fn get_full_path() -> String {
std::any::type_name::<Self>().into()
}
}
/// Generate [`IdlBuild`] impl for a struct.
/// Generate `IdlBuild` impl for a struct.
pub fn impl_idl_build_struct(item: &syn::ItemStruct) -> TokenStream {
impl_idl_build(&item.ident, &item.generics, gen_idl_type_def_struct(item))
}
/// Generate [`IdlBuild`] impl for an enum.
/// Generate `IdlBuild` impl for an enum.
pub fn impl_idl_build_enum(item: &syn::ItemEnum) -> TokenStream {
impl_idl_build(&item.ident, &item.generics, gen_idl_type_def_enum(item))
}
/// Generate [`IdlBuild`] impl for a union.
/// Generate `IdlBuild` impl for a union.
///
/// Unions are not currently supported in the IDL.
pub fn impl_idl_build_union(item: &syn::ItemUnion) -> TokenStream {
@ -60,7 +26,7 @@ pub fn impl_idl_build_union(item: &syn::ItemUnion) -> TokenStream {
)
}
/// Generate [`IdlBuild`] implementation.
/// Generate `IdlBuild` implementation.
fn impl_idl_build(
ident: &syn::Ident,
generics: &syn::Generics,
@ -68,7 +34,7 @@ fn impl_idl_build(
) -> TokenStream {
let idl = get_idl_module_path();
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let idl_build_trait = quote!(anchor_lang::anchor_syn::idl::build::IdlBuild);
let idl_build_trait = quote!(anchor_lang::idl::build::IdlBuild);
let (idl_type_def, insert_defined) = match type_def {
Ok((ts, defined)) => (
@ -577,9 +543,12 @@ pub fn gen_idl_type(
.enumerate()
.fold(outer, |acc, (i, cur)| {
let inner = &inners[i];
acc.replace(&format!(" {cur}"), &format!(" {inner} "))
// The spacing of the `outer` variable can differ between
// versions, e.g. `[T; N]` and `[T ; N]`
acc.replace(&format!(" {cur} "), &format!(" {inner} "))
.replace(&format!(" {cur},"), &format!(" {inner},"))
.replace(&format!("[{cur} "), &format!("[{inner} ",))
.replace(&format!("[{cur} "), &format!("[{inner} "))
.replace(&format!("[{cur};"), &format!("[{inner};"))
.replace(&format!(" {cur}]"), &format!(" {inner}]"))
});
if let Ok(ty) = syn::parse_str(&resolved_alias) {

View File

@ -1,4 +1,19 @@
pub mod types;
#![allow(dead_code)]
#[cfg(feature = "idl-build")]
pub mod build;
mod accounts;
mod address;
mod common;
mod constant;
mod defined;
mod error;
mod event;
mod external;
mod program;
pub use accounts::gen_idl_build_impl_accounts_struct;
pub use address::gen_idl_print_fn_address;
pub use constant::gen_idl_print_fn_constant;
pub use defined::{impl_idl_build_enum, impl_idl_build_struct, impl_idl_build_union};
pub use error::gen_idl_print_fn_error;
pub use event::gen_idl_print_fn_event;
pub use program::gen_idl_print_fn_program;

View File

@ -119,6 +119,7 @@ pub fn gen_idl_print_fn_program(program: &Program) -> TokenStream {
.map(|r| r.into()),
dependencies: Default::default(),
contact: Default::default(),
deployments: Default::default(),
},
docs: #docs,
instructions: vec![#(#instructions),*],

View File

@ -1,486 +0,0 @@
use std::str::FromStr;
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
/// IDL specification Semantic Version
pub const IDL_SPEC: &str = "0.1.0";
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Idl {
pub address: String,
pub metadata: IdlMetadata,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
pub instructions: Vec<IdlInstruction>,
#[serde(default, skip_serializing_if = "is_default")]
pub accounts: Vec<IdlAccount>,
#[serde(default, skip_serializing_if = "is_default")]
pub events: Vec<IdlEvent>,
#[serde(default, skip_serializing_if = "is_default")]
pub errors: Vec<IdlErrorCode>,
#[serde(default, skip_serializing_if = "is_default")]
pub types: Vec<IdlTypeDef>,
#[serde(default, skip_serializing_if = "is_default")]
pub constants: Vec<IdlConst>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlMetadata {
pub name: String,
pub version: String,
pub spec: String,
#[serde(skip_serializing_if = "is_default")]
pub description: Option<String>,
#[serde(skip_serializing_if = "is_default")]
pub repository: Option<String>,
#[serde(default, skip_serializing_if = "is_default")]
pub dependencies: Vec<IdlDependency>,
#[serde(skip_serializing_if = "is_default")]
pub contact: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlDependency {
pub name: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlInstruction {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
pub discriminator: IdlDiscriminator,
pub accounts: Vec<IdlInstructionAccountItem>,
pub args: Vec<IdlField>,
#[serde(skip_serializing_if = "is_default")]
pub returns: Option<IdlType>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum IdlInstructionAccountItem {
Composite(IdlInstructionAccounts),
Single(IdlInstructionAccount),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlInstructionAccount {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(default, skip_serializing_if = "is_default")]
pub writable: bool,
#[serde(default, skip_serializing_if = "is_default")]
pub signer: bool,
#[serde(default, skip_serializing_if = "is_default")]
pub optional: bool,
#[serde(skip_serializing_if = "is_default")]
pub address: Option<String>,
#[serde(skip_serializing_if = "is_default")]
pub pda: Option<IdlPda>,
#[serde(default, skip_serializing_if = "is_default")]
pub relations: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlInstructionAccounts {
pub name: String,
pub accounts: Vec<IdlInstructionAccountItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlPda {
pub seeds: Vec<IdlSeed>,
#[serde(skip_serializing_if = "is_default")]
pub program: Option<IdlSeed>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlSeed {
Const(IdlSeedConst),
Arg(IdlSeedArg),
Account(IdlSeedAccount),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlSeedConst {
pub value: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlSeedArg {
pub path: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlSeedAccount {
pub path: String,
#[serde(skip_serializing_if = "is_default")]
pub account: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlAccount {
pub name: String,
pub discriminator: IdlDiscriminator,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlEvent {
pub name: String,
pub discriminator: IdlDiscriminator,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlConst {
pub name: String,
#[serde(rename = "type")]
pub ty: IdlType,
pub value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct IdlErrorCode {
pub code: u32,
pub name: String,
#[serde(skip_serializing_if = "is_default")]
pub msg: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlField {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(rename = "type")]
pub ty: IdlType,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlTypeDef {
pub name: String,
#[serde(default, skip_serializing_if = "is_default")]
pub docs: Vec<String>,
#[serde(default, skip_serializing_if = "is_default")]
pub serialization: IdlSerialization,
#[serde(skip_serializing_if = "is_default")]
pub repr: Option<IdlRepr>,
#[serde(default, skip_serializing_if = "is_default")]
pub generics: Vec<IdlTypeDefGeneric>,
#[serde(rename = "type")]
pub ty: IdlTypeDefTy,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum IdlSerialization {
#[default]
Borsh,
Bytemuck,
BytemuckUnsafe,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlRepr {
Rust(IdlReprModifier),
C(IdlReprModifier),
Transparent,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlReprModifier {
#[serde(default, skip_serializing_if = "is_default")]
pub packed: bool,
#[serde(skip_serializing_if = "is_default")]
pub align: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlTypeDefGeneric {
Type {
name: String,
},
Const {
name: String,
#[serde(rename = "type")]
ty: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlTypeDefTy {
Struct {
#[serde(skip_serializing_if = "is_default")]
fields: Option<IdlDefinedFields>,
},
Enum {
variants: Vec<IdlEnumVariant>,
},
Type {
alias: IdlType,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdlEnumVariant {
pub name: String,
#[serde(skip_serializing_if = "is_default")]
pub fields: Option<IdlDefinedFields>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum IdlDefinedFields {
Named(Vec<IdlField>),
Tuple(Vec<IdlType>),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum IdlArrayLen {
Generic(String),
#[serde(untagged)]
Value(usize),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum IdlGenericArg {
Type {
#[serde(rename = "type")]
ty: IdlType,
},
Const {
value: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum IdlType {
Bool,
U8,
I8,
U16,
I16,
U32,
I32,
F32,
U64,
I64,
F64,
U128,
I128,
U256,
I256,
Bytes,
String,
Pubkey,
Option(Box<IdlType>),
Vec(Box<IdlType>),
Array(Box<IdlType>, IdlArrayLen),
Defined {
name: String,
#[serde(default, skip_serializing_if = "is_default")]
generics: Vec<IdlGenericArg>,
},
Generic(String),
}
impl FromStr for IdlType {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut s = s.to_owned();
s.retain(|c| !c.is_whitespace());
let r = match s.as_str() {
"bool" => IdlType::Bool,
"u8" => IdlType::U8,
"i8" => IdlType::I8,
"u16" => IdlType::U16,
"i16" => IdlType::I16,
"u32" => IdlType::U32,
"i32" => IdlType::I32,
"f32" => IdlType::F32,
"u64" => IdlType::U64,
"i64" => IdlType::I64,
"f64" => IdlType::F64,
"u128" => IdlType::U128,
"i128" => IdlType::I128,
"u256" => IdlType::U256,
"i256" => IdlType::I256,
"Vec<u8>" => IdlType::Bytes,
"String" | "&str" | "&'staticstr" => IdlType::String,
"Pubkey" => IdlType::Pubkey,
_ => {
if let Some(inner) = s.strip_prefix("Option<") {
let inner_ty = Self::from_str(
inner
.strip_suffix('>')
.ok_or_else(|| anyhow!("Invalid Option"))?,
)?;
return Ok(IdlType::Option(Box::new(inner_ty)));
}
if let Some(inner) = s.strip_prefix("Vec<") {
let inner_ty = Self::from_str(
inner
.strip_suffix('>')
.ok_or_else(|| anyhow!("Invalid Vec"))?,
)?;
return Ok(IdlType::Vec(Box::new(inner_ty)));
}
if s.starts_with('[') {
fn array_from_str(inner: &str) -> IdlType {
match inner.strip_suffix(']') {
Some(nested_inner) => array_from_str(&nested_inner[1..]),
None => {
let (raw_type, raw_length) = inner.rsplit_once(';').unwrap();
let ty = IdlType::from_str(raw_type).unwrap();
let len = match raw_length.replace('_', "").parse::<usize>() {
Ok(len) => IdlArrayLen::Value(len),
Err(_) => IdlArrayLen::Generic(raw_length.to_owned()),
};
IdlType::Array(Box::new(ty), len)
}
}
}
return Ok(array_from_str(&s));
}
// Defined
let (name, generics) = if let Some(i) = s.find('<') {
(
s.get(..i).unwrap().to_owned(),
s.get(i + 1..)
.unwrap()
.strip_suffix('>')
.unwrap()
.split(',')
.map(|g| g.trim().to_owned())
.map(|g| {
if g.parse::<bool>().is_ok()
|| g.parse::<u128>().is_ok()
|| g.parse::<i128>().is_ok()
|| g.parse::<char>().is_ok()
{
Ok(IdlGenericArg::Const { value: g })
} else {
Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty })
}
})
.collect::<Result<Vec<_>, _>>()?,
)
} else {
(s.to_owned(), vec![])
};
IdlType::Defined { name, generics }
}
};
Ok(r)
}
}
pub type IdlDiscriminator = Vec<u8>;
/// Get whether the given data is the default of its type.
fn is_default<T: Default + PartialEq>(it: &T) -> bool {
*it == T::default()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn option() {
assert_eq!(
IdlType::from_str("Option<bool>").unwrap(),
IdlType::Option(Box::new(IdlType::Bool))
)
}
#[test]
fn vector() {
assert_eq!(
IdlType::from_str("Vec<bool>").unwrap(),
IdlType::Vec(Box::new(IdlType::Bool))
)
}
#[test]
fn array() {
assert_eq!(
IdlType::from_str("[Pubkey; 16]").unwrap(),
IdlType::Array(Box::new(IdlType::Pubkey), IdlArrayLen::Value(16))
);
}
#[test]
fn array_with_underscored_length() {
assert_eq!(
IdlType::from_str("[u8; 50_000]").unwrap(),
IdlType::Array(Box::new(IdlType::U8), IdlArrayLen::Value(50000))
);
}
#[test]
fn multidimensional_array() {
assert_eq!(
IdlType::from_str("[[u8; 16]; 32]").unwrap(),
IdlType::Array(
Box::new(IdlType::Array(
Box::new(IdlType::U8),
IdlArrayLen::Value(16)
)),
IdlArrayLen::Value(32)
)
);
}
#[test]
fn generic_array() {
assert_eq!(
IdlType::from_str("[u64; T]").unwrap(),
IdlType::Array(Box::new(IdlType::U64), IdlArrayLen::Generic("T".into()))
);
}
#[test]
fn defined() {
assert_eq!(
IdlType::from_str("MyStruct").unwrap(),
IdlType::Defined {
name: "MyStruct".into(),
generics: vec![]
}
)
}
#[test]
fn defined_with_generics() {
assert_eq!(
IdlType::from_str("MyStruct<Pubkey, u64, 8>").unwrap(),
IdlType::Defined {
name: "MyStruct".into(),
generics: vec![
IdlGenericArg::Type {
ty: IdlType::Pubkey
},
IdlGenericArg::Type { ty: IdlType::U64 },
IdlGenericArg::Const { value: "8".into() },
],
}
)
}
}

View File

@ -3,7 +3,7 @@
pub mod codegen;
pub mod parser;
#[cfg(feature = "idl-types")]
#[cfg(feature = "idl-build")]
pub mod idl;
#[cfg(feature = "hash")]
@ -680,6 +680,21 @@ pub enum ConstraintToken {
Realloc(Context<ConstraintRealloc>),
ReallocPayer(Context<ConstraintReallocPayer>),
ReallocZero(Context<ConstraintReallocZero>),
// extensions
ExtensionGroupPointerAuthority(Context<ConstraintExtensionAuthority>),
ExtensionGroupPointerGroupAddress(Context<ConstraintExtensionGroupPointerGroupAddress>),
ExtensionGroupMemberPointerAuthority(Context<ConstraintExtensionAuthority>),
ExtensionGroupMemberPointerMemberAddress(
Context<ConstraintExtensionGroupMemberPointerMemberAddress>,
),
ExtensionMetadataPointerAuthority(Context<ConstraintExtensionAuthority>),
ExtensionMetadataPointerMetadataAddress(
Context<ConstraintExtensionMetadataPointerMetadataAddress>,
),
ExtensionCloseAuthority(Context<ConstraintExtensionAuthority>),
ExtensionTokenHookAuthority(Context<ConstraintExtensionAuthority>),
ExtensionTokenHookProgramId(Context<ConstraintExtensionTokenHookProgramId>),
ExtensionPermanentDelegate(Context<ConstraintExtensionPermanentDelegate>),
}
impl Parse for ConstraintToken {
@ -796,6 +811,37 @@ pub struct ConstraintSpace {
pub space: Expr,
}
// extension constraints
#[derive(Debug, Clone)]
pub struct ConstraintExtensionAuthority {
pub authority: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintExtensionGroupPointerGroupAddress {
pub group_address: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintExtensionGroupMemberPointerMemberAddress {
pub member_address: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintExtensionMetadataPointerMetadataAddress {
pub metadata_address: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintExtensionTokenHookProgramId {
pub program_id: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintExtensionPermanentDelegate {
pub permanent_delegate: Expr,
}
#[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum InitKind {
@ -822,6 +868,17 @@ pub enum InitKind {
freeze_authority: Option<Expr>,
decimals: Expr,
token_program: Option<Expr>,
// extensions
group_pointer_authority: Option<Expr>,
group_pointer_group_address: Option<Expr>,
group_member_pointer_authority: Option<Expr>,
group_member_pointer_member_address: Option<Expr>,
metadata_pointer_authority: Option<Expr>,
metadata_pointer_metadata_address: Option<Expr>,
close_authority: Option<Expr>,
permanent_delegate: Option<Expr>,
transfer_hook_authority: Option<Expr>,
transfer_hook_program_id: Option<Expr>,
},
}
@ -835,6 +892,46 @@ pub struct ConstraintTokenMint {
pub mint: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintConfidentialTransferData {
pub confidential_transfer_data: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintMetadata {
pub token_metadata: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintTokenGroupData {
pub token_group_data: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintTokenGroupMemberData {
pub token_group_member_data: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintMetadataPointerData {
pub metadata_pointer_data: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintGroupPointerData {
pub group_pointer_data: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintGroupMemberPointerData {
pub group_member_pointer_data: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintMintCloseAuthority {
pub close_authority: Expr,
}
#[derive(Debug, Clone)]
pub struct ConstraintTokenAuthority {
pub auth: Expr,
@ -890,6 +987,16 @@ pub struct ConstraintTokenMintGroup {
pub mint_authority: Option<Expr>,
pub freeze_authority: Option<Expr>,
pub token_program: Option<Expr>,
pub group_pointer_authority: Option<Expr>,
pub group_pointer_group_address: Option<Expr>,
pub group_member_pointer_authority: Option<Expr>,
pub group_member_pointer_member_address: Option<Expr>,
pub metadata_pointer_authority: Option<Expr>,
pub metadata_pointer_metadata_address: Option<Expr>,
pub close_authority: Option<Expr>,
pub permanent_delegate: Option<Expr>,
pub transfer_hook_authority: Option<Expr>,
pub transfer_hook_program_id: Option<Expr>,
}
// Syntaxt context object for preserving metadata about the inner item.

View File

@ -1,10 +1,6 @@
use crate::*;
use syn::ext::IdentExt;
use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::{bracketed, Expr, Ident, Token};
use syn::parse::{Error as ParseError, Result as ParseResult};
use syn::{bracketed, Token};
pub fn parse(f: &syn::Field, f_ty: Option<&Ty>) -> ParseResult<ConstraintGroup> {
let mut constraints = ConstraintGroupBuilder::new(f_ty);
@ -93,6 +89,177 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"extensions" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
match kw.as_str() {
"group_pointer" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;
let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
match kw.as_str() {
"authority" => {
ConstraintToken::ExtensionGroupPointerAuthority(Context::new(
span,
ConstraintExtensionAuthority {
authority: stream.parse()?,
},
))
}
"group_address" => {
ConstraintToken::ExtensionGroupPointerGroupAddress(Context::new(
span,
ConstraintExtensionGroupPointerGroupAddress {
group_address: stream.parse()?,
},
))
}
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"group_member_pointer" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;
let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
match kw.as_str() {
"authority" => {
ConstraintToken::ExtensionGroupMemberPointerAuthority(Context::new(
span,
ConstraintExtensionAuthority {
authority: stream.parse()?,
},
))
}
"member_address" => {
ConstraintToken::ExtensionGroupMemberPointerMemberAddress(Context::new(
span,
ConstraintExtensionGroupMemberPointerMemberAddress {
member_address: stream.parse()?,
},
))
}
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"metadata_pointer" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;
let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
match kw.as_str() {
"authority" => {
ConstraintToken::ExtensionMetadataPointerAuthority(Context::new(
span,
ConstraintExtensionAuthority {
authority: stream.parse()?,
},
))
}
"metadata_address" => {
ConstraintToken::ExtensionMetadataPointerMetadataAddress(Context::new(
span,
ConstraintExtensionMetadataPointerMetadataAddress {
metadata_address: stream.parse()?,
},
))
}
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"close_authority" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;
let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
match kw.as_str() {
"authority" => ConstraintToken::ExtensionCloseAuthority(Context::new(
span,
ConstraintExtensionAuthority {
authority: stream.parse()?,
},
)),
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"permanent_delegate" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;
let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
match kw.as_str() {
"delegate" => ConstraintToken::ExtensionPermanentDelegate(Context::new(
span,
ConstraintExtensionPermanentDelegate {
permanent_delegate: stream.parse()?,
},
)),
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"transfer_hook" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;
let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());
match kw.as_str() {
"authority" => ConstraintToken::ExtensionTokenHookAuthority(Context::new(
span,
ConstraintExtensionAuthority {
authority: stream.parse()?,
},
)),
"program_id" => ConstraintToken::ExtensionTokenHookProgramId(Context::new(
span,
ConstraintExtensionTokenHookProgramId {
program_id: stream.parse()?,
},
)),
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"token" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
@ -358,6 +525,19 @@ pub struct ConstraintGroupBuilder<'ty> {
pub mint_freeze_authority: Option<Context<ConstraintMintFreezeAuthority>>,
pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
pub mint_token_program: Option<Context<ConstraintTokenProgram>>,
pub extension_group_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_group_pointer_group_address:
Option<Context<ConstraintExtensionGroupPointerGroupAddress>>,
pub extension_group_member_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_group_member_pointer_member_address:
Option<Context<ConstraintExtensionGroupMemberPointerMemberAddress>>,
pub extension_metadata_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_metadata_pointer_metadata_address:
Option<Context<ConstraintExtensionMetadataPointerMetadataAddress>>,
pub extension_close_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_transfer_hook_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_transfer_hook_program_id: Option<Context<ConstraintExtensionTokenHookProgramId>>,
pub extension_permanent_delegate: Option<Context<ConstraintExtensionPermanentDelegate>>,
pub bump: Option<Context<ConstraintTokenBump>>,
pub program_seed: Option<Context<ConstraintProgramSeed>>,
pub realloc: Option<Context<ConstraintRealloc>>,
@ -393,6 +573,16 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
mint_freeze_authority: None,
mint_decimals: None,
mint_token_program: None,
extension_group_pointer_authority: None,
extension_group_pointer_group_address: None,
extension_group_member_pointer_authority: None,
extension_group_member_pointer_member_address: None,
extension_metadata_pointer_authority: None,
extension_metadata_pointer_metadata_address: None,
extension_close_authority: None,
extension_transfer_hook_authority: None,
extension_transfer_hook_program_id: None,
extension_permanent_delegate: None,
bump: None,
program_seed: None,
realloc: None,
@ -595,6 +785,16 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
mint_freeze_authority,
mint_decimals,
mint_token_program,
extension_group_pointer_authority,
extension_group_pointer_group_address,
extension_group_member_pointer_authority,
extension_group_member_pointer_member_address,
extension_metadata_pointer_authority,
extension_metadata_pointer_metadata_address,
extension_close_authority,
extension_transfer_hook_authority,
extension_transfer_hook_program_id,
extension_permanent_delegate,
bump,
program_seed,
realloc,
@ -684,8 +884,33 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
&mint_authority,
&mint_freeze_authority,
&mint_token_program,
&extension_group_pointer_authority,
&extension_group_pointer_group_address,
&extension_group_member_pointer_authority,
&extension_group_member_pointer_member_address,
&extension_metadata_pointer_authority,
&extension_metadata_pointer_metadata_address,
&extension_close_authority,
&extension_transfer_hook_authority,
&extension_transfer_hook_program_id,
&extension_permanent_delegate,
) {
(None, None, None, None) => None,
(
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
) => None,
_ => Some(ConstraintTokenMintGroup {
decimals: mint_decimals
.as_ref()
@ -699,6 +924,37 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
token_program: mint_token_program
.as_ref()
.map(|a| a.clone().into_inner().token_program),
// extensions
group_pointer_authority: extension_group_pointer_authority
.as_ref()
.map(|a| a.clone().into_inner().authority),
group_pointer_group_address: extension_group_pointer_group_address
.as_ref()
.map(|a| a.clone().into_inner().group_address),
group_member_pointer_authority: extension_group_member_pointer_authority
.as_ref()
.map(|a| a.clone().into_inner().authority),
group_member_pointer_member_address: extension_group_member_pointer_member_address
.as_ref()
.map(|a| a.clone().into_inner().member_address),
metadata_pointer_authority: extension_metadata_pointer_authority
.as_ref()
.map(|a| a.clone().into_inner().authority),
metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address
.as_ref()
.map(|a| a.clone().into_inner().metadata_address),
close_authority: extension_close_authority
.as_ref()
.map(|a| a.clone().into_inner().authority),
permanent_delegate: extension_permanent_delegate
.as_ref()
.map(|a| a.clone().into_inner().permanent_delegate),
transfer_hook_authority: extension_transfer_hook_authority
.as_ref()
.map(|a| a.clone().into_inner().authority),
transfer_hook_program_id: extension_transfer_hook_program_id
.as_ref()
.map(|a| a.clone().into_inner().program_id),
}),
};
@ -738,6 +994,17 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
},
freeze_authority: mint_freeze_authority.map(|fa| fa.into_inner().mint_freeze_auth),
token_program: mint_token_program.map(|tp| tp.into_inner().token_program),
// extensions
group_pointer_authority: extension_group_pointer_authority.map(|gpa| gpa.into_inner().authority),
group_pointer_group_address: extension_group_pointer_group_address.map(|gpga| gpga.into_inner().group_address),
group_member_pointer_authority: extension_group_member_pointer_authority.map(|gmpa| gmpa.into_inner().authority),
group_member_pointer_member_address: extension_group_member_pointer_member_address.map(|gmpma| gmpma.into_inner().member_address),
metadata_pointer_authority: extension_metadata_pointer_authority.map(|mpa| mpa.into_inner().authority),
metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address.map(|mpma| mpma.into_inner().metadata_address),
close_authority: extension_close_authority.map(|ca| ca.into_inner().authority),
permanent_delegate: extension_permanent_delegate.map(|pd| pd.into_inner().permanent_delegate),
transfer_hook_authority: extension_transfer_hook_authority.map(|tha| tha.into_inner().authority),
transfer_hook_program_id: extension_transfer_hook_program_id.map(|thpid| thpid.into_inner().program_id),
}
} else {
InitKind::Program {
@ -800,6 +1067,32 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
ConstraintToken::Realloc(c) => self.add_realloc(c),
ConstraintToken::ReallocPayer(c) => self.add_realloc_payer(c),
ConstraintToken::ReallocZero(c) => self.add_realloc_zero(c),
ConstraintToken::ExtensionGroupPointerAuthority(c) => {
self.add_extension_group_pointer_authority(c)
}
ConstraintToken::ExtensionGroupPointerGroupAddress(c) => {
self.add_extension_group_pointer_group_address(c)
}
ConstraintToken::ExtensionGroupMemberPointerAuthority(c) => {
self.add_extension_group_member_pointer_authority(c)
}
ConstraintToken::ExtensionGroupMemberPointerMemberAddress(c) => {
self.add_extension_group_member_pointer_member_address(c)
}
ConstraintToken::ExtensionMetadataPointerAuthority(c) => {
self.add_extension_metadata_pointer_authority(c)
}
ConstraintToken::ExtensionMetadataPointerMetadataAddress(c) => {
self.add_extension_metadata_pointer_metadata_address(c)
}
ConstraintToken::ExtensionCloseAuthority(c) => self.add_extension_close_authority(c),
ConstraintToken::ExtensionTokenHookAuthority(c) => self.add_extension_authority(c),
ConstraintToken::ExtensionTokenHookProgramId(c) => {
self.add_extension_transfer_hook_program_id(c)
}
ConstraintToken::ExtensionPermanentDelegate(c) => {
self.add_extension_permanent_delegate(c)
}
}
}
@ -1225,4 +1518,147 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
self.space.replace(c);
Ok(())
}
// extensions
fn add_extension_group_pointer_authority(
&mut self,
c: Context<ConstraintExtensionAuthority>,
) -> ParseResult<()> {
if self.extension_group_pointer_authority.is_some() {
return Err(ParseError::new(
c.span(),
"extension group pointer authority already provided",
));
}
self.extension_group_pointer_authority.replace(c);
Ok(())
}
fn add_extension_group_pointer_group_address(
&mut self,
c: Context<ConstraintExtensionGroupPointerGroupAddress>,
) -> ParseResult<()> {
if self.extension_group_pointer_group_address.is_some() {
return Err(ParseError::new(
c.span(),
"extension group pointer group address already provided",
));
}
self.extension_group_pointer_group_address.replace(c);
Ok(())
}
fn add_extension_group_member_pointer_authority(
&mut self,
c: Context<ConstraintExtensionAuthority>,
) -> ParseResult<()> {
if self.extension_group_member_pointer_authority.is_some() {
return Err(ParseError::new(
c.span(),
"extension group member pointer authority already provided",
));
}
self.extension_group_member_pointer_authority.replace(c);
Ok(())
}
fn add_extension_group_member_pointer_member_address(
&mut self,
c: Context<ConstraintExtensionGroupMemberPointerMemberAddress>,
) -> ParseResult<()> {
if self.extension_group_member_pointer_member_address.is_some() {
return Err(ParseError::new(
c.span(),
"extension group member pointer member address already provided",
));
}
self.extension_group_member_pointer_member_address
.replace(c);
Ok(())
}
fn add_extension_metadata_pointer_authority(
&mut self,
c: Context<ConstraintExtensionAuthority>,
) -> ParseResult<()> {
if self.extension_metadata_pointer_authority.is_some() {
return Err(ParseError::new(
c.span(),
"extension metadata pointer authority already provided",
));
}
self.extension_metadata_pointer_authority.replace(c);
Ok(())
}
fn add_extension_metadata_pointer_metadata_address(
&mut self,
c: Context<ConstraintExtensionMetadataPointerMetadataAddress>,
) -> ParseResult<()> {
if self.extension_metadata_pointer_metadata_address.is_some() {
return Err(ParseError::new(
c.span(),
"extension metadata pointer metadata address already provided",
));
}
self.extension_metadata_pointer_metadata_address.replace(c);
Ok(())
}
fn add_extension_close_authority(
&mut self,
c: Context<ConstraintExtensionAuthority>,
) -> ParseResult<()> {
if self.extension_close_authority.is_some() {
return Err(ParseError::new(
c.span(),
"extension close authority already provided",
));
}
self.extension_close_authority.replace(c);
Ok(())
}
fn add_extension_authority(
&mut self,
c: Context<ConstraintExtensionAuthority>,
) -> ParseResult<()> {
if self.extension_transfer_hook_authority.is_some() {
return Err(ParseError::new(
c.span(),
"extension transfer hook authority already provided",
));
}
self.extension_transfer_hook_authority.replace(c);
Ok(())
}
fn add_extension_transfer_hook_program_id(
&mut self,
c: Context<ConstraintExtensionTokenHookProgramId>,
) -> ParseResult<()> {
if self.extension_transfer_hook_program_id.is_some() {
return Err(ParseError::new(
c.span(),
"extension transfer hook program id already provided",
));
}
self.extension_transfer_hook_program_id.replace(c);
Ok(())
}
fn add_extension_permanent_delegate(
&mut self,
c: Context<ConstraintExtensionPermanentDelegate>,
) -> ParseResult<()> {
if self.extension_permanent_delegate.is_some() {
return Err(ParseError::new(
c.span(),
"extension permanent delegate already provided",
));
}
self.extension_permanent_delegate.replace(c);
Ok(())
}
}

View File

@ -5,10 +5,6 @@ pub mod event_cpi;
use crate::parser::docs;
use crate::*;
use syn::parse::{Error as ParseError, Result as ParseResult};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::Expr;
use syn::Path;
pub fn parse(accounts_struct: &syn::ItemStruct) -> ParseResult<AccountsStruct> {

View File

@ -12,7 +12,7 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
default = ["associated_token", "mint", "token", "token_2022"]
default = ["associated_token", "mint", "token", "token_2022", "token_2022_extensions"]
associated_token = ["spl-associated-token-account"]
dex = ["serum_dex"]
devnet = []
@ -24,18 +24,17 @@ mint = []
stake = ["borsh"]
token = ["spl-token"]
token_2022 = ["spl-token-2022"]
token_2022_extensions = ["spl-token-2022", "spl-token-group-interface", "spl-token-metadata-interface", "spl-pod"]
[dependencies]
anchor-lang = { path = "../lang", version = "0.29.0", features = ["derive"] }
borsh = { version = ">=0.9, <0.11", optional = true }
mpl-token-metadata = { version = "3.1.0", optional = true }
mpl-token-metadata = { version = "4", optional = true }
serum_dex = { git = "https://github.com/openbook-dex/program/", rev = "1be91f2", version = "0.4.0", features = ["no-entrypoint"], optional = true }
solana-program = "1.16"
spl-associated-token-account = { version = "2.2", features = ["no-entrypoint"], optional = true }
spl-associated-token-account = { version = "3", features = ["no-entrypoint"], optional = true }
spl-memo = { version = "4", features = ["no-entrypoint"], optional = true }
spl-token = { version = "4", features = ["no-entrypoint"], optional = true }
spl-token-2022 = { version = "3", features = ["no-entrypoint"], optional = true }
# TODO: Remove after https://github.com/coral-xyz/anchor/pull/2795 is merged.
# `toml_edit 0.21.1` has MSRV of `1.69.0` which is above `1.68.0` that comes from `solana-cli 1.17`.
toml_edit = "=0.21.0"
spl-token-group-interface = { version = "0.2.3", optional = true }
spl-token-metadata-interface = { version = "0.3.3", optional = true }
spl-pod = { version = "0.2.2", optional = true }

View File

@ -14,7 +14,7 @@ pub fn create<'info>(ctx: CpiContext<'_, '_, '_, 'info, Create<'info>>) -> Resul
ctx.accounts.mint.key,
ctx.accounts.token_program.key,
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.payer,
@ -38,7 +38,7 @@ pub fn create_idempotent<'info>(
ctx.accounts.mint.key,
ctx.accounts.token_program.key,
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.payer,

View File

@ -9,10 +9,10 @@ use std::num::NonZeroU64;
pub use serum_dex;
#[cfg(not(feature = "devnet"))]
anchor_lang::solana_program::declare_id!("srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX");
anchor_lang::declare_id!("srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX");
#[cfg(feature = "devnet")]
anchor_lang::solana_program::declare_id!("EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj");
anchor_lang::declare_id!("EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj");
#[allow(clippy::too_many_arguments)]
pub fn new_order_v3<'info>(
@ -52,7 +52,7 @@ pub fn new_order_v3<'info>(
max_native_pc_qty_including_fees,
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -77,7 +77,7 @@ pub fn cancel_order_v2<'info>(
order_id,
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -101,7 +101,7 @@ pub fn settle_funds<'info>(ctx: CpiContext<'_, '_, '_, 'info, SettleFunds<'info>
ctx.accounts.vault_signer.key,
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -120,7 +120,7 @@ pub fn init_open_orders<'info>(
ctx.remaining_accounts.first().map(|acc| acc.key),
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -139,7 +139,7 @@ pub fn close_open_orders<'info>(
ctx.accounts.market.key,
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -158,7 +158,7 @@ pub fn sweep_fees<'info>(ctx: CpiContext<'_, '_, '_, 'info, SweepFees<'info>>) -
ctx.accounts.token_program.key,
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -194,7 +194,7 @@ pub fn initialize_market<'info>(
pc_dust_threshold,
)
.map_err(|pe| ProgramError::from(pe))?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,

View File

@ -12,7 +12,7 @@ macro_rules! vote_weight_record {
let vwr: spl_governance_addin_api::voter_weight::VoterWeightRecord =
anchor_lang::AnchorDeserialize::deserialize(&mut data)
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?;
if !solana_program::program_pack::IsInitialized::is_initialized(&vwr) {
if !anchor_lang::solana_program::program_pack::IsInitialized::is_initialized(&vwr) {
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}
Ok(VoterWeightRecord(vwr))

View File

@ -14,6 +14,9 @@ pub mod token;
#[cfg(feature = "token_2022")]
pub mod token_2022;
#[cfg(feature = "token_2022_extensions")]
pub mod token_2022_extensions;
#[cfg(feature = "token_2022")]
pub mod token_interface;

View File

@ -13,8 +13,12 @@ pub fn build_memo<'info>(ctx: CpiContext<'_, '_, '_, 'info, BuildMemo>, memo: &[
.map(|account| account.key)
.collect::<Vec<_>>(),
);
solana_program::program::invoke_signed(&ix, &ctx.remaining_accounts, ctx.signer_seeds)
.map_err(Into::into)
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ctx.remaining_accounts,
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]

View File

@ -1,9 +1,9 @@
use anchor_lang::context::CpiContext;
use anchor_lang::error::ErrorCode;
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::solana_program::sysvar;
use anchor_lang::{system_program, Accounts, Result, ToAccountInfos};
use solana_program::account_info::AccountInfo;
use solana_program::pubkey::Pubkey;
use solana_program::sysvar;
use std::ops::Deref;
pub use mpl_token_metadata;
@ -23,7 +23,7 @@ pub fn approve_collection_authority<'info>(
update_authority: *ctx.accounts.update_authority.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -48,7 +48,7 @@ pub fn bubblegum_set_collection_size<'info>(
set_collection_size_args: mpl_token_metadata::types::SetCollectionSizeArgs { size },
},
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -72,7 +72,7 @@ pub fn burn_edition_nft<'info>(
spl_token_program: *ctx.accounts.spl_token.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -109,7 +109,7 @@ pub fn burn_nft<'info>(
token_account: *ctx.accounts.token.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -143,7 +143,7 @@ pub fn create_metadata_accounts_v3<'info>(
is_mutable,
},
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -170,7 +170,7 @@ pub fn update_metadata_accounts_v2<'info>(
is_mutable,
},
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -196,7 +196,7 @@ pub fn create_master_edition_v3<'info>(
.instruction(
mpl_token_metadata::instructions::CreateMasterEditionV3InstructionArgs { max_supply },
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -230,7 +230,7 @@ pub fn mint_new_edition_from_master_edition_via_token<'info>(
mpl_token_metadata::types::MintNewEditionFromMasterEditionViaTokenArgs { edition },
},
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -249,7 +249,7 @@ pub fn revoke_collection_authority<'info>(
revoke_authority: *ctx.accounts.revoke_authority.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -273,7 +273,7 @@ pub fn set_collection_size<'info>(
set_collection_size_args: mpl_token_metadata::types::SetCollectionSizeArgs { size },
},
);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -295,7 +295,7 @@ pub fn verify_collection<'info>(
payer: *ctx.accounts.payer.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -317,7 +317,7 @@ pub fn verify_sized_collection_item<'info>(
payer: *ctx.accounts.payer.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -340,7 +340,7 @@ pub fn set_and_verify_collection<'info>(
update_authority: *ctx.accounts.update_authority.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -363,7 +363,7 @@ pub fn set_and_verify_sized_collection_item<'info>(
update_authority: *ctx.accounts.update_authority.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -382,7 +382,7 @@ pub fn freeze_delegated_account<'info>(
token_program: *ctx.accounts.token_program.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -401,7 +401,7 @@ pub fn thaw_delegated_account<'info>(
token_program: *ctx.accounts.token_program.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -418,7 +418,7 @@ pub fn update_primary_sale_happened_via_token<'info>(
token: *ctx.accounts.token.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -437,7 +437,7 @@ pub fn set_token_standard<'info>(
update_authority: *ctx.accounts.update_authority.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -451,7 +451,7 @@ pub fn sign_metadata<'info>(ctx: CpiContext<'_, '_, '_, 'info, SignMetadata<'inf
metadata: *ctx.accounts.metadata.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -467,7 +467,7 @@ pub fn remove_creator_verification<'info>(
metadata: *ctx.accounts.metadata.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -495,7 +495,7 @@ pub fn utilize<'info>(
use_authority_record,
}
.instruction(mpl_token_metadata::instructions::UtilizeInstructionArgs { number_of_uses });
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -516,7 +516,7 @@ pub fn unverify_collection<'info>(
metadata: *ctx.accounts.metadata.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,
@ -538,7 +538,7 @@ pub fn unverify_sized_collection_item<'info>(
payer: *ctx.accounts.payer.key,
}
.instruction();
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&ToAccountInfos::to_account_infos(&ctx),
ctx.signer_seeds,

View File

@ -1,4 +1,4 @@
use anchor_lang::solana_program::declare_id;
use anchor_lang::declare_id;
pub use srm::ID as SRM;
mod srm {

View File

@ -36,7 +36,7 @@ pub fn authorize<'info>(
if let Some(c) = custodian {
account_infos.push(c);
}
solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
.map_err(Into::into)
}
@ -62,7 +62,7 @@ pub fn withdraw<'info>(
if let Some(c) = custodian {
account_infos.push(c);
}
solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
.map_err(Into::into)
}
@ -70,7 +70,7 @@ pub fn deactivate_stake<'info>(
ctx: CpiContext<'_, '_, '_, 'info, DeactivateStake<'info>>,
) -> Result<()> {
let ix = stake::instruction::deactivate_stake(ctx.accounts.stake.key, ctx.accounts.staker.key);
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.stake, ctx.accounts.clock, ctx.accounts.staker],
ctx.signer_seeds,

View File

@ -1,9 +1,8 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::program_pack::Pack;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
use anchor_lang::{solana_program, Result};
use std::ops::Deref;
pub use spl_token;
@ -21,7 +20,7 @@ pub fn transfer<'info>(
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.from, ctx.accounts.to, ctx.accounts.authority],
ctx.signer_seeds,
@ -44,7 +43,7 @@ pub fn transfer_checked<'info>(
amount,
decimals,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.from,
@ -69,7 +68,7 @@ pub fn mint_to<'info>(
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
ctx.signer_seeds,
@ -86,7 +85,7 @@ pub fn burn<'info>(ctx: CpiContext<'_, '_, '_, 'info, Burn<'info>>, amount: u64)
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
ctx.signer_seeds,
@ -106,7 +105,7 @@ pub fn approve<'info>(
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.to,
@ -133,7 +132,7 @@ pub fn approve_checked<'info>(
amount,
decimals,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.to,
@ -153,7 +152,7 @@ pub fn revoke<'info>(ctx: CpiContext<'_, '_, '_, 'info, Revoke<'info>>) -> Resul
ctx.accounts.authority.key,
&[],
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.source, ctx.accounts.authority],
ctx.signer_seeds,
@ -170,7 +169,7 @@ pub fn initialize_account<'info>(
ctx.accounts.mint.key,
ctx.accounts.authority.key,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -192,7 +191,7 @@ pub fn initialize_account3<'info>(
ctx.accounts.mint.key,
ctx.accounts.authority.key,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.account, ctx.accounts.mint],
ctx.signer_seeds,
@ -208,7 +207,7 @@ pub fn close_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, CloseAccount<'inf
ctx.accounts.authority.key,
&[], // TODO: support multisig
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -230,7 +229,7 @@ pub fn freeze_account<'info>(
ctx.accounts.authority.key,
&[], // TODO: Support multisig signers.
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -250,7 +249,7 @@ pub fn thaw_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, ThawAccount<'info>
ctx.accounts.authority.key,
&[], // TODO: Support multisig signers.
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -275,7 +274,7 @@ pub fn initialize_mint<'info>(
freeze_authority,
decimals,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.mint, ctx.accounts.rent],
ctx.signer_seeds,
@ -296,7 +295,7 @@ pub fn initialize_mint2<'info>(
freeze_authority,
decimals,
)?;
solana_program::program::invoke_signed(&ix, &[ctx.accounts.mint], ctx.signer_seeds)
anchor_lang::solana_program::program::invoke_signed(&ix, &[ctx.accounts.mint], ctx.signer_seeds)
.map_err(Into::into)
}
@ -318,7 +317,7 @@ pub fn set_authority<'info>(
ctx.accounts.current_authority.key,
&[], // TODO: Support multisig signers.
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.account_or_mint, ctx.accounts.current_authority],
ctx.signer_seeds,
@ -328,8 +327,12 @@ pub fn set_authority<'info>(
pub fn sync_native<'info>(ctx: CpiContext<'_, '_, '_, 'info, SyncNative<'info>>) -> Result<()> {
let ix = spl_token::instruction::sync_native(&spl_token::ID, ctx.accounts.account.key)?;
solana_program::program::invoke_signed(&ix, &[ctx.accounts.account], ctx.signer_seeds)
.map_err(Into::into)
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.account],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
@ -440,7 +443,7 @@ pub struct SyncNative<'info> {
pub account: AccountInfo<'info>,
}
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq, Copy)]
pub struct TokenAccount(spl_token::state::Account);
impl TokenAccount {
@ -471,7 +474,7 @@ impl Deref for TokenAccount {
}
}
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq, Copy)]
pub struct Mint(spl_token::state::Mint);
impl Mint {

View File

@ -1,8 +1,7 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
use anchor_lang::{solana_program, Result};
pub use spl_token_2022;
pub use spl_token_2022::ID;
@ -24,7 +23,7 @@ pub fn transfer<'info>(
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.from, ctx.accounts.to, ctx.accounts.authority],
ctx.signer_seeds,
@ -47,7 +46,7 @@ pub fn transfer_checked<'info>(
amount,
decimals,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.from,
@ -72,7 +71,7 @@ pub fn mint_to<'info>(
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
ctx.signer_seeds,
@ -89,7 +88,7 @@ pub fn burn<'info>(ctx: CpiContext<'_, '_, '_, 'info, Burn<'info>>, amount: u64)
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
ctx.signer_seeds,
@ -109,7 +108,7 @@ pub fn approve<'info>(
&[],
amount,
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.to,
@ -128,7 +127,7 @@ pub fn revoke<'info>(ctx: CpiContext<'_, '_, '_, 'info, Revoke<'info>>) -> Resul
ctx.accounts.authority.key,
&[],
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.source, ctx.accounts.authority],
ctx.signer_seeds,
@ -145,7 +144,7 @@ pub fn initialize_account<'info>(
ctx.accounts.mint.key,
ctx.accounts.authority.key,
)?;
solana_program::program::invoke(
anchor_lang::solana_program::program::invoke(
&ix,
&[
ctx.accounts.account,
@ -166,7 +165,7 @@ pub fn initialize_account3<'info>(
ctx.accounts.mint.key,
ctx.accounts.authority.key,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.account, ctx.accounts.mint])
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account, ctx.accounts.mint])
.map_err(Into::into)
}
@ -178,7 +177,7 @@ pub fn close_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, CloseAccount<'inf
ctx.accounts.authority.key,
&[], // TODO: support multisig
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -200,7 +199,7 @@ pub fn freeze_account<'info>(
ctx.accounts.authority.key,
&[], // TODO: Support multisig signers.
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -220,7 +219,7 @@ pub fn thaw_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, ThawAccount<'info>
ctx.accounts.authority.key,
&[], // TODO: Support multisig signers.
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.account,
@ -245,7 +244,7 @@ pub fn initialize_mint<'info>(
freeze_authority,
decimals,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.mint, ctx.accounts.rent])
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint, ctx.accounts.rent])
.map_err(Into::into)
}
@ -262,7 +261,7 @@ pub fn initialize_mint2<'info>(
freeze_authority,
decimals,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
}
pub fn set_authority<'info>(
@ -283,7 +282,7 @@ pub fn set_authority<'info>(
ctx.accounts.current_authority.key,
&[], // TODO: Support multisig signers.
)?;
solana_program::program::invoke_signed(
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.account_or_mint, ctx.accounts.current_authority],
ctx.signer_seeds,
@ -293,7 +292,7 @@ pub fn set_authority<'info>(
pub fn sync_native<'info>(ctx: CpiContext<'_, '_, '_, 'info, SyncNative<'info>>) -> Result<()> {
let ix = spl_token_2022::instruction::sync_native(ctx.program.key, ctx.accounts.account.key)?;
solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
}
pub fn get_account_data_size<'info>(
@ -305,15 +304,15 @@ pub fn get_account_data_size<'info>(
ctx.accounts.mint.key,
extension_types,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.mint])?;
solana_program::program::get_return_data()
.ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint])?;
anchor_lang::solana_program::program::get_return_data()
.ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
.and_then(|(key, data)| {
if key != *ctx.program.key {
Err(solana_program::program_error::ProgramError::IncorrectProgramId)
Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
} else {
data.try_into().map(u64::from_le_bytes).map_err(|_| {
solana_program::program_error::ProgramError::InvalidInstructionData
anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
})
}
})
@ -329,7 +328,7 @@ pub fn initialize_mint_close_authority<'info>(
ctx.accounts.mint.key,
close_authority,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
}
pub fn initialize_immutable_owner<'info>(
@ -339,7 +338,7 @@ pub fn initialize_immutable_owner<'info>(
ctx.program.key,
ctx.accounts.account.key,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
}
pub fn amount_to_ui_amount<'info>(
@ -351,15 +350,15 @@ pub fn amount_to_ui_amount<'info>(
ctx.accounts.account.key,
amount,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
solana_program::program::get_return_data()
.ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
anchor_lang::solana_program::program::get_return_data()
.ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
.and_then(|(key, data)| {
if key != *ctx.program.key {
Err(solana_program::program_error::ProgramError::IncorrectProgramId)
Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
} else {
String::from_utf8(data).map_err(|_| {
solana_program::program_error::ProgramError::InvalidInstructionData
anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
})
}
})
@ -375,15 +374,15 @@ pub fn ui_amount_to_amount<'info>(
ctx.accounts.account.key,
ui_amount,
)?;
solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
solana_program::program::get_return_data()
.ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
anchor_lang::solana_program::program::get_return_data()
.ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
.and_then(|(key, data)| {
if key != *ctx.program.key {
Err(solana_program::program_error::ProgramError::IncorrectProgramId)
Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
} else {
data.try_into().map(u64::from_le_bytes).map_err(|_| {
solana_program::program_error::ProgramError::InvalidInstructionData
anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
})
}
})
@ -523,7 +522,3 @@ impl anchor_lang::Id for Token2022 {
ID
}
}
// Field parsers to save compute. All account validation is assumed to be done
// outside of these methods.
pub use crate::token::accessor;

View File

@ -0,0 +1 @@
// waiting for labs to merge

View File

@ -0,0 +1 @@
// waiting for labs to merge

View File

@ -0,0 +1,50 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn cpi_guard_enable<'info>(ctx: CpiContext<'_, '_, '_, 'info, CpiGuard<'info>>) -> Result<()> {
let ix = spl_token_2022::extension::cpi_guard::instruction::enable_cpi_guard(
ctx.accounts.token_program_id.key,
ctx.accounts.account.key,
ctx.accounts.account.owner,
&[],
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.account,
ctx.accounts.owner,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
pub fn cpi_guard_disable<'info>(ctx: CpiContext<'_, '_, '_, 'info, CpiGuard<'info>>) -> Result<()> {
let ix = spl_token_2022::extension::cpi_guard::instruction::disable_cpi_guard(
ctx.accounts.token_program_id.key,
ctx.accounts.account.key,
ctx.accounts.account.owner,
&[],
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.account,
ctx.accounts.owner,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct CpiGuard<'info> {
pub token_program_id: AccountInfo<'info>,
pub account: AccountInfo<'info>,
pub owner: AccountInfo<'info>,
}

View File

@ -0,0 +1,59 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
use spl_token_2022::state::AccountState;
pub fn default_account_state_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, DefaultAccountStateInitialize<'info>>,
state: &AccountState,
) -> Result<()> {
let ix = spl_token_2022::extension::default_account_state::instruction::initialize_default_account_state(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
state
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct DefaultAccountStateInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn default_account_state_update<'info>(
ctx: CpiContext<'_, '_, '_, 'info, DefaultAccountStateUpdate<'info>>,
state: &AccountState,
) -> Result<()> {
let ix = spl_token_2022::extension::default_account_state::instruction::update_default_account_state(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.freeze_authority.key,
&[],
state
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.mint,
ctx.accounts.freeze_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct DefaultAccountStateUpdate<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub freeze_authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,59 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn group_member_pointer_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, GroupMemberPointerInitialize<'info>>,
authority: Option<Pubkey>,
member_address: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::group_member_pointer::instruction::initialize(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
authority,
member_address,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct GroupMemberPointerInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn group_member_pointer_update<'info>(
ctx: CpiContext<'_, '_, '_, 'info, GroupMemberPointerUpdate<'info>>,
member_address: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::group_member_pointer::instruction::update(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.authority.key,
&[],
member_address,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.mint,
ctx.accounts.authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct GroupMemberPointerUpdate<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,55 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn group_pointer_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, GroupPointerInitialize<'info>>,
authority: Option<Pubkey>,
group_address: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::group_pointer::instruction::initialize(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
authority,
group_address,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct GroupPointerInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn group_pointer_update<'info>(
ctx: CpiContext<'_, '_, '_, 'info, GroupPointerUpdate<'info>>,
group_address: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::group_pointer::instruction::update(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.authority.key,
&[&ctx.accounts.authority.key],
group_address,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct GroupPointerUpdate<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,25 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn immutable_owner_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, ImmutableOwnerInitialize<'info>>,
) -> Result<()> {
let ix = spl_token_2022::instruction::initialize_immutable_owner(
ctx.accounts.token_program_id.key,
ctx.accounts.token_account.key,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.token_account],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct ImmutableOwnerInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub token_account: AccountInfo<'info>,
}

View File

@ -0,0 +1,59 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn interest_bearing_mint_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, InterestBearingMintInitialize<'info>>,
rate_authority: Option<Pubkey>,
rate: i16,
) -> Result<()> {
let ix = spl_token_2022::extension::interest_bearing_mint::instruction::initialize(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
rate_authority,
rate,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct InterestBearingMintInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn interest_bearing_mint_update_rate<'info>(
ctx: CpiContext<'_, '_, '_, 'info, InterestBearingMintUpdateRate<'info>>,
rate: i16,
) -> Result<()> {
let ix = spl_token_2022::extension::interest_bearing_mint::instruction::update_rate(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.rate_authority.key,
&[],
rate,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.mint,
ctx.accounts.rate_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct InterestBearingMintUpdateRate<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub rate_authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,54 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn memo_transfer_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, MemoTransfer<'info>>,
) -> Result<()> {
let ix = spl_token_2022::extension::memo_transfer::instruction::enable_required_transfer_memos(
ctx.accounts.token_program_id.key,
ctx.accounts.account.key,
ctx.accounts.owner.key,
&[],
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.account,
ctx.accounts.owner,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
pub fn memo_transfer_disable<'info>(
ctx: CpiContext<'_, '_, '_, 'info, MemoTransfer<'info>>,
) -> Result<()> {
let ix =
spl_token_2022::extension::memo_transfer::instruction::disable_required_transfer_memos(
ctx.accounts.token_program_id.key,
ctx.accounts.account.key,
ctx.accounts.owner.key,
&[],
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.account,
ctx.accounts.owner,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct MemoTransfer<'info> {
pub token_program_id: AccountInfo<'info>,
pub account: AccountInfo<'info>,
pub owner: AccountInfo<'info>,
}

View File

@ -0,0 +1,29 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn metadata_pointer_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, MetadataPointerInitialize<'info>>,
authority: Option<Pubkey>,
metadata_address: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::metadata_pointer::instruction::initialize(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
authority,
metadata_address,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct MetadataPointerInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}

View File

@ -0,0 +1,27 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn mint_close_authority_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, MintCloseAuthorityInitialize<'info>>,
authority: Option<&Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::instruction::initialize_mint_close_authority(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
authority,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct MintCloseAuthorityInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}

View File

@ -0,0 +1,36 @@
pub mod confidential_transfer;
pub mod confidential_transfer_fee;
pub mod cpi_guard;
pub mod default_account_state;
pub mod group_member_pointer;
pub mod group_pointer;
pub mod immutable_owner;
pub mod interest_bearing_mint;
pub mod memo_transfer;
pub mod metadata_pointer;
pub mod mint_close_authority;
pub mod non_transferable;
pub mod permanent_delegate;
pub mod token_group;
pub mod token_metadata;
pub mod transfer_fee;
pub mod transfer_hook;
pub use cpi_guard::*;
pub use default_account_state::*;
pub use group_member_pointer::*;
pub use group_pointer::*;
pub use immutable_owner::*;
pub use interest_bearing_mint::*;
pub use memo_transfer::*;
pub use metadata_pointer::*;
pub use mint_close_authority::*;
pub use non_transferable::*;
pub use permanent_delegate::*;
pub use token_group::*;
pub use token_metadata::*;
pub use transfer_fee::*;
pub use transfer_hook::*;
pub use spl_pod;
pub use spl_token_metadata_interface;

View File

@ -0,0 +1,25 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn non_transferable_mint_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, NonTransferableMintInitialize<'info>>,
) -> Result<()> {
let ix = spl_token_2022::instruction::initialize_non_transferable_mint(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct NonTransferableMintInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}

View File

@ -0,0 +1,27 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn permanent_delegate_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, PermanentDelegateInitialize<'info>>,
permanent_delegate: &Pubkey,
) -> Result<()> {
let ix = spl_token_2022::instruction::initialize_permanent_delegate(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
permanent_delegate,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct PermanentDelegateInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}

View File

@ -0,0 +1,74 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn token_group_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TokenGroupInitialize<'info>>,
update_authority: Option<Pubkey>,
max_size: u32,
) -> Result<()> {
let ix = spl_token_group_interface::instruction::initialize_group(
ctx.accounts.token_program_id.key,
ctx.accounts.group.key,
ctx.accounts.mint.key,
ctx.accounts.mint_authority.key,
update_authority,
max_size,
);
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.group,
ctx.accounts.mint,
ctx.accounts.mint_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TokenGroupInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub group: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub mint_authority: AccountInfo<'info>,
}
pub fn token_member_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TokenMemberInitialize<'info>>,
) -> Result<()> {
let ix = spl_token_group_interface::instruction::initialize_member(
ctx.accounts.token_program_id.key,
ctx.accounts.member.key,
ctx.accounts.member_mint.key,
ctx.accounts.member_mint_authority.key,
ctx.accounts.group.key,
ctx.accounts.group_update_authority.key,
);
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.member,
ctx.accounts.member_mint,
ctx.accounts.member_mint_authority,
ctx.accounts.group,
ctx.accounts.group_update_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TokenMemberInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub member: AccountInfo<'info>,
pub member_mint: AccountInfo<'info>,
pub member_mint_authority: AccountInfo<'info>,
pub group: AccountInfo<'info>,
pub group_update_authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,107 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
use spl_pod::optional_keys::OptionalNonZeroPubkey;
use spl_token_metadata_interface::state::Field;
pub fn token_metadata_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TokenMetadataInitialize<'info>>,
name: String,
symbol: String,
uri: String,
) -> Result<()> {
let ix = spl_token_metadata_interface::instruction::initialize(
ctx.accounts.token_program_id.key,
ctx.accounts.metadata.key,
ctx.accounts.update_authority.key,
ctx.accounts.mint.key,
ctx.accounts.mint_authority.key,
name,
symbol,
uri,
);
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.metadata,
ctx.accounts.update_authority,
ctx.accounts.mint,
ctx.accounts.mint_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TokenMetadataInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub metadata: AccountInfo<'info>,
pub update_authority: AccountInfo<'info>,
pub mint_authority: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn token_metadata_update_authority<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TokenMetadataUpdateAuthority<'info>>,
new_authority: OptionalNonZeroPubkey,
) -> Result<()> {
let ix = spl_token_metadata_interface::instruction::update_authority(
ctx.accounts.token_program_id.key,
ctx.accounts.metadata.key,
ctx.accounts.current_authority.key,
new_authority,
);
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.metadata,
ctx.accounts.current_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TokenMetadataUpdateAuthority<'info> {
pub token_program_id: AccountInfo<'info>,
pub metadata: AccountInfo<'info>,
pub current_authority: AccountInfo<'info>,
pub new_authority: AccountInfo<'info>,
}
pub fn token_metadata_update_field<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TokenMetadataUpdateField<'info>>,
field: Field,
value: String,
) -> Result<()> {
let ix = spl_token_metadata_interface::instruction::update_field(
ctx.accounts.token_program_id.key,
ctx.accounts.metadata.key,
ctx.accounts.update_authority.key,
field,
value,
);
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.metadata,
ctx.accounts.update_authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TokenMetadataUpdateField<'info> {
pub token_program_id: AccountInfo<'info>,
pub metadata: AccountInfo<'info>,
pub update_authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,160 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn transfer_fee_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TransferFeeInitialize<'info>>,
transfer_fee_config_authority: Option<&Pubkey>,
withdraw_withheld_authority: Option<&Pubkey>,
transfer_fee_basis_points: u16,
maximum_fee: u64,
) -> Result<()> {
let ix = spl_token_2022::extension::transfer_fee::instruction::initialize_transfer_fee_config(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
transfer_fee_config_authority,
withdraw_withheld_authority,
transfer_fee_basis_points,
maximum_fee,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TransferFeeInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn transfer_fee_set<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TransferFeeSetTransferFee<'info>>,
transfer_fee_basis_points: u16,
maximum_fee: u64,
) -> Result<()> {
let ix = spl_token_2022::extension::transfer_fee::instruction::set_transfer_fee(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.authority.key,
&[],
transfer_fee_basis_points,
maximum_fee,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.mint,
ctx.accounts.authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TransferFeeSetTransferFee<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
}
pub fn transfer_checked_with_fee<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TransferCheckedWithFee<'info>>,
amount: u64,
decimals: u8,
fee: u64,
) -> Result<()> {
let ix = spl_token_2022::extension::transfer_fee::instruction::transfer_checked_with_fee(
ctx.accounts.token_program_id.key,
ctx.accounts.source.key,
ctx.accounts.mint.key,
ctx.accounts.destination.key,
ctx.accounts.authority.key,
&[],
amount,
decimals,
fee,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.source,
ctx.accounts.mint,
ctx.accounts.destination,
ctx.accounts.authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TransferCheckedWithFee<'info> {
pub token_program_id: AccountInfo<'info>,
pub source: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub destination: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
}
pub fn harvest_withheld_tokens_to_mint<'info>(
ctx: CpiContext<'_, '_, '_, 'info, HarvestWithheldTokensToMint<'info>>,
sources: Vec<AccountInfo<'info>>,
) -> Result<()> {
let ix = spl_token_2022::extension::transfer_fee::instruction::harvest_withheld_tokens_to_mint(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
sources.iter().map(|a| a.key).collect::<Vec<_>>().as_slice(),
)?;
let mut account_infos = vec![ctx.accounts.token_program_id, ctx.accounts.mint];
account_infos.extend_from_slice(&sources);
anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct HarvestWithheldTokensToMint<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn withdraw_withheld_tokens_from_mint<'info>(
ctx: CpiContext<'_, '_, '_, 'info, WithdrawWithheldTokensFromMint<'info>>,
) -> Result<()> {
let ix =
spl_token_2022::extension::transfer_fee::instruction::withdraw_withheld_tokens_from_mint(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.destination.key,
ctx.accounts.authority.key,
&[],
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.mint,
ctx.accounts.destination,
ctx.accounts.authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct WithdrawWithheldTokensFromMint<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub destination: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
}

View File

@ -0,0 +1,59 @@
use anchor_lang::solana_program::account_info::AccountInfo;
use anchor_lang::solana_program::pubkey::Pubkey;
use anchor_lang::Result;
use anchor_lang::{context::CpiContext, Accounts};
pub fn transfer_hook_initialize<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TransferHookInitialize<'info>>,
authority: Option<Pubkey>,
transfer_hook_program_id: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::transfer_hook::instruction::initialize(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
authority,
transfer_hook_program_id,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[ctx.accounts.token_program_id, ctx.accounts.mint],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TransferHookInitialize<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
}
pub fn transfer_hook_update<'info>(
ctx: CpiContext<'_, '_, '_, 'info, TransferHookUpdate<'info>>,
transfer_hook_program_id: Option<Pubkey>,
) -> Result<()> {
let ix = spl_token_2022::extension::transfer_hook::instruction::update(
ctx.accounts.token_program_id.key,
ctx.accounts.mint.key,
ctx.accounts.authority.key,
&[],
transfer_hook_program_id,
)?;
anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.token_program_id,
ctx.accounts.mint,
ctx.accounts.authority,
],
ctx.signer_seeds,
)
.map_err(Into::into)
}
#[derive(Accounts)]
pub struct TransferHookUpdate<'info> {
pub token_program_id: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
}

View File

@ -1,11 +1,19 @@
use anchor_lang::solana_program::program_pack::Pack;
use anchor_lang::solana_program::pubkey::Pubkey;
use spl_token_2022::extension::ExtensionType;
use spl_token_2022::{
extension::{BaseStateWithExtensions, Extension, StateWithExtensions},
solana_zk_token_sdk::instruction::Pod,
};
use std::ops::Deref;
pub use crate::token_2022::*;
#[cfg(feature = "token_2022_extensions")]
pub use crate::token_2022_extensions::*;
static IDS: [Pubkey; 2] = [spl_token::ID, spl_token_2022::ID];
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq, Copy)]
pub struct TokenAccount(spl_token_2022::state::Account);
impl anchor_lang::AccountDeserialize for TokenAccount {
@ -34,7 +42,7 @@ impl Deref for TokenAccount {
}
}
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq, Copy)]
pub struct Mint(spl_token_2022::state::Mint);
impl anchor_lang::AccountDeserialize for Mint {
@ -69,3 +77,25 @@ impl anchor_lang::Ids for TokenInterface {
&IDS
}
}
pub type ExtensionsVec = Vec<ExtensionType>;
pub fn find_mint_account_size(extensions: Option<&ExtensionsVec>) -> anchor_lang::Result<usize> {
if let Some(extensions) = extensions {
Ok(ExtensionType::try_calculate_account_len::<
spl_token_2022::state::Mint,
>(extensions)?)
} else {
Ok(spl_token_2022::state::Mint::LEN)
}
}
pub fn get_mint_extension_data<T: Extension + Pod>(
account: &anchor_lang::solana_program::account_info::AccountInfo,
) -> anchor_lang::Result<T> {
let mint_data = account.data.borrow();
let mint_with_extension =
StateWithExtensions::<spl_token_2022::state::Mint>::unpack(&mint_data)?;
let extension_data = *mint_with_extension.get_extension::<T>()?;
Ok(extension_data)
}

View File

@ -80,6 +80,48 @@
"type": "u32"
}
]
},
{
"name": "update_composite",
"discriminator": [
26,
42,
201,
224,
121,
60,
188,
220
],
"accounts": [
{
"name": "update",
"accounts": [
{
"name": "authority",
"signer": true
},
{
"name": "my_account",
"writable": true,
"pda": {
"seeds": [
{
"kind": "account",
"path": "authority"
}
]
}
}
]
}
],
"args": [
{
"name": "value",
"type": "u32"
}
]
}
],
"accounts": [
@ -97,6 +139,21 @@
]
}
],
"events": [
{
"name": "MyEvent",
"discriminator": [
96,
184,
197,
243,
139,
2,
90,
148
]
}
],
"types": [
{
"name": "MyAccount",
@ -109,6 +166,18 @@
}
]
}
},
{
"name": "MyEvent",
"type": {
"kind": "struct",
"fields": [
{
"name": "value",
"type": "u32"
}
]
}
}
]
}

View File

@ -28,6 +28,51 @@ pub mod declare_program {
Ok(())
}
pub fn cpi_composite(ctx: Context<Cpi>, value: u32) -> Result<()> {
let cpi_my_account = &mut ctx.accounts.cpi_my_account;
let cpi_ctx = CpiContext::new(
ctx.accounts.external_program.to_account_info(),
external::cpi::accounts::UpdateComposite {
update: external::cpi::accounts::Update {
authority: ctx.accounts.authority.to_account_info(),
my_account: cpi_my_account.to_account_info(),
},
},
);
external::cpi::update_composite(cpi_ctx, value)?;
cpi_my_account.reload()?;
require_eq!(cpi_my_account.field, value);
Ok(())
}
pub fn event_utils(_ctx: Context<Utils>) -> Result<()> {
use external::utils::Event;
// Empty
if Event::try_from_bytes(&[]).is_ok() {
return Err(ProgramError::Custom(0).into());
}
const DISC: &[u8] =
&<external::events::MyEvent as anchor_lang::Discriminator>::DISCRIMINATOR;
// Correct discriminator but invalid data
if Event::try_from_bytes(DISC).is_ok() {
return Err(ProgramError::Custom(1).into());
};
// Correct discriminator and valid data
match Event::try_from_bytes(&[DISC, &[1, 0, 0, 0]].concat()) {
Ok(Event::MyEvent(my_event)) => require_eq!(my_event.value, 1),
Err(e) => return Err(e.into()),
}
Ok(())
}
}
#[derive(Accounts)]
@ -37,3 +82,8 @@ pub struct Cpi<'info> {
pub cpi_my_account: Account<'info, external::accounts::MyAccount>,
pub external_program: Program<'info, External>,
}
#[derive(Accounts)]
pub struct Utils<'info> {
pub authority: Signer<'info>,
}

View File

@ -14,6 +14,11 @@ pub mod external {
ctx.accounts.my_account.field = value;
Ok(())
}
pub fn update_composite(ctx: Context<UpdateComposite>, value: u32) -> Result<()> {
ctx.accounts.update.my_account.field = value;
Ok(())
}
}
#[derive(Accounts)]
@ -38,7 +43,17 @@ pub struct Update<'info> {
pub my_account: Account<'info, MyAccount>,
}
#[derive(Accounts)]
pub struct UpdateComposite<'info> {
pub update: Update<'info>,
}
#[account]
pub struct MyAccount {
pub field: u32,
}
#[event]
pub struct MyEvent {
pub value: u32,
}

View File

@ -10,9 +10,18 @@ describe("declare-program", () => {
anchor.workspace.declareProgram;
const externalProgram: anchor.Program<External> = anchor.workspace.external;
it("Can CPI", async () => {
const { pubkeys } = await externalProgram.methods.init().rpcAndKeys();
// TODO: Add a utility type that does this?
let pubkeys: Awaited<
ReturnType<
ReturnType<typeof externalProgram["methods"]["init"]>["rpcAndKeys"]
>
>["pubkeys"];
before(async () => {
pubkeys = (await externalProgram.methods.init().rpcAndKeys()).pubkeys;
});
it("Can CPI", async () => {
const value = 5;
await program.methods
.cpi(value)
@ -24,4 +33,21 @@ describe("declare-program", () => {
);
assert.strictEqual(myAccount.field, value);
});
it("Can CPI composite", async () => {
const value = 3;
await program.methods
.cpiComposite(value)
.accounts({ cpiMyAccount: pubkeys.myAccount })
.rpc();
const myAccount = await externalProgram.account.myAccount.fetch(
pubkeys.myAccount
);
assert.strictEqual(myAccount.field, value);
});
it("Can use event utils", async () => {
await program.methods.eventUtils().rpc();
});
});

View File

@ -4,6 +4,10 @@ use anchor_lang::prelude::*;
declare_id!("Docs111111111111111111111111111111111111111");
/// Documentation comment for constant
#[constant]
pub const MY_CONST: u8 = 42;
/// This is a doc comment for the program
#[program]
pub mod docs {

View File

@ -366,7 +366,7 @@ mod wrapped {
use super::*;
#[cfg(feature = "idl-build")]
use anchor_lang::anchor_syn::idl::types::*;
use anchor_lang::idl::types::*;
pub struct Feature(anchor_lang::solana_program::feature::Feature);

View File

@ -42,4 +42,9 @@ describe("Docs", () => {
"Account attribute doc comment should appear in the IDL",
]);
});
it("includes constant doc comment", () => {
const myConst = program.idl.constants.find((c) => c.name === "myConst")!;
assert.deepEqual(myConst.docs, ["Documentation comment for constant"]);
});
});

Some files were not shown because too many files have changed in this diff Show More