Compare commits
21 Commits
41bd980242
...
1d65b1a30d
Author | SHA1 | Date |
---|---|---|
cavemanloverboy | 1d65b1a30d | |
acheron | 95c4959287 | |
Bhargava Sai Macha | a18d6caa6d | |
acheron | 7356bd5afe | |
acheron | 1f0bf0ee60 | |
Bhargava Sai Macha | e3ced784ad | |
acheron | ae26fd84bb | |
acheron | 0be5b00a34 | |
acheron | c7ccbb8f62 | |
acheron | 3591ba6cb8 | |
acheron | 01839ad725 | |
acheron | cbf9b0a090 | |
acheron | da2d9a4045 | |
acheron | 2dd79da674 | |
acheron | 5f6af05519 | |
acheron | 4de70aabee | |
acheron | c138a55b72 | |
cavemanloverboy | c51a838aa4 | |
cavemanloverboy | 9e5bfe18ae | |
cavemanloverboy | 12349b4a2f | |
cavemanloverboy | 1644bc8623 |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:?}"),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"node": ">=11"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "anchor test --skip-lint"
|
||||
"test": "anchor test --skip-lint && anchor clean"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"node": ">=11"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "anchor test --skip-lint"
|
||||
"test": "anchor test --skip-lint && anchor clean"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"node": ">=11"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "anchor test --skip-lint"
|
||||
"test": "anchor test --skip-lint && anchor clean"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"node": ">=11"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "anchor test --skip-lint"
|
||||
"test": "anchor test --skip-lint && anchor clean"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"node": ">=11"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "anchor test --skip-lint"
|
||||
"test": "anchor test --skip-lint && anchor clean"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -4,3 +4,6 @@ pub mod types;
|
|||
|
||||
#[cfg(feature = "build")]
|
||||
pub mod build;
|
||||
|
||||
#[cfg(feature = "build")]
|
||||
pub use serde_json;
|
||||
|
|
502
idl/src/types.rs
502
idl/src/types.rs
|
@ -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() },
|
||||
],
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] }
|
|
@ -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},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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}");
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_syn::idl::types::Idl;
|
||||
use anchor_idl::types::Idl;
|
||||
use quote::quote;
|
||||
|
||||
use super::common::gen_accounts_common;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_syn::idl::types::Idl;
|
||||
use anchor_idl::types::Idl;
|
||||
use heck::CamelCase;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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! {
|
||||
|
|
|
@ -6,5 +6,6 @@ pub mod events;
|
|||
pub mod internal;
|
||||
pub mod program;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
use super::common;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, *};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = []
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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 {
|
|
@ -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),
|
||||
}
|
|
@ -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) {
|
|
@ -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;
|
||||
|
|
|
@ -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),*],
|
|
@ -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() },
|
||||
],
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_lang::solana_program::declare_id;
|
||||
use anchor_lang::declare_id;
|
||||
|
||||
pub use srm::ID as SRM;
|
||||
mod srm {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
// waiting for labs to merge
|
|
@ -0,0 +1 @@
|
|||
// waiting for labs to merge
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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;
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue