Compare commits
19 Commits
cf654dce2f
...
16afd7148e
Author | SHA1 | Date |
---|---|---|
tilacog | 16afd7148e | |
acheron | f74ea64ca6 | |
acheron | 257b560109 | |
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 | |
tilacog | fabe183aeb |
|
@ -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,11 @@ 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)).
|
||||
- lang: Return overflow error from `Lamports` trait operations ([#2907](https://github.com/coral-xyz/anchor/pull/2907)).
|
||||
|
||||
### Fixes
|
||||
|
||||
|
@ -66,6 +71,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
|
||||
|
||||
|
@ -88,6 +96,7 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
- 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,7 +170,7 @@ dependencies = [
|
|||
name = "anchor-attribute-program"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"anchor-idl",
|
||||
"anchor-lang-idl",
|
||||
"anchor-syn",
|
||||
"anyhow",
|
||||
"bs58 0.5.0",
|
||||
|
@ -186,8 +186,8 @@ name = "anchor-cli"
|
|||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"anchor-client",
|
||||
"anchor-idl",
|
||||
"anchor-lang",
|
||||
"anchor-lang-idl",
|
||||
"anyhow",
|
||||
"base64 0.21.7",
|
||||
"bincode",
|
||||
|
@ -263,17 +263,6 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anchor-idl"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"anchor-syn",
|
||||
"anyhow",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anchor-lang"
|
||||
version = "0.29.0"
|
||||
|
@ -287,7 +276,7 @@ dependencies = [
|
|||
"anchor-derive-accounts",
|
||||
"anchor-derive-serde",
|
||||
"anchor-derive-space",
|
||||
"anchor-idl",
|
||||
"anchor-lang-idl",
|
||||
"arrayref",
|
||||
"base64 0.21.7",
|
||||
"bincode",
|
||||
|
@ -298,6 +287,17 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anchor-lang-idl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anchor-syn",
|
||||
"anyhow",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anchor-spl"
|
||||
version = "0.29.0"
|
||||
|
@ -306,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]]
|
||||
|
@ -2531,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",
|
||||
|
@ -4523,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",
|
||||
|
@ -4683,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"
|
||||
|
@ -4764,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",
|
||||
|
@ -4847,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",
|
||||
]
|
||||
|
@ -4911,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",
|
||||
|
@ -4953,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",
|
||||
]
|
||||
|
||||
|
@ -4979,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",
|
||||
]
|
||||
|
@ -5008,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",
|
||||
|
@ -5039,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-lang-idl = { path = "../idl", features = ["build"], version = "0.1.0" }
|
||||
anchor-lang = { path = "../lang", version = "0.29.0" }
|
||||
anyhow = "1.0.32"
|
||||
base64 = "0.21"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::is_hidden;
|
||||
use anchor_client::Cluster;
|
||||
use anchor_idl::types::Idl;
|
||||
use anchor_lang_idl::types::Idl;
|
||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use dirs::home_dir;
|
||||
|
|
|
@ -6,9 +6,9 @@ use crate::config::{
|
|||
DEFAULT_LEDGER_PATH, SHUTDOWN_WAIT, STARTUP_WAIT,
|
||||
};
|
||||
use anchor_client::Cluster;
|
||||
use anchor_idl::types::{Idl, IdlArrayLen, IdlDefinedFields, IdlType, IdlTypeDefTy};
|
||||
use anchor_lang::idl::{IdlAccount, IdlInstruction, ERASED_AUTHORITY};
|
||||
use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize};
|
||||
use anchor_lang_idl::types::{Idl, IdlArrayLen, IdlDefinedFields, IdlType, IdlTypeDefTy};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use checks::{check_anchor_version, check_overflow};
|
||||
use clap::Parser;
|
||||
|
@ -2609,7 +2609,7 @@ fn idl_build(
|
|||
.path
|
||||
}
|
||||
};
|
||||
let idl = anchor_idl::build::build_idl(
|
||||
let idl = anchor_lang_idl::build::build_idl(
|
||||
program_path,
|
||||
cfg.features.resolution,
|
||||
cfg.features.skip_lint || skip_lint,
|
||||
|
@ -2655,7 +2655,7 @@ in `{path}`."#
|
|||
));
|
||||
}
|
||||
|
||||
anchor_idl::build::build_idl(
|
||||
anchor_lang_idl::build::build_idl(
|
||||
std::env::current_dir()?,
|
||||
cfg.features.resolution,
|
||||
cfg.features.skip_lint || skip_lint,
|
||||
|
@ -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:?}"),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
config::ProgramWorkspace, create_files, override_or_create_files, solidity_template, Files,
|
||||
VERSION,
|
||||
};
|
||||
use anchor_idl::types::Idl;
|
||||
use anchor_lang_idl::types::Idl;
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use heck::{ToLowerCamelCase, ToPascalCase, ToSnakeCase};
|
||||
|
|
|
@ -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"
|
||||
name = "anchor-lang-idl"
|
||||
version = "0.1.0"
|
||||
authors = ["Anchor Maintainers <accounts@200ms.io>"]
|
||||
repository = "https://github.com/coral-xyz/anchor"
|
||||
rust-version = "1.60"
|
||||
|
|
|
@ -67,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,7 +4,7 @@ use anyhow::anyhow;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// IDL specification Semantic Version
|
||||
pub const IDL_SPEC: &str = "0.1.0";
|
||||
pub const IDL_SPEC: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Idl {
|
||||
|
@ -38,6 +38,8 @@ pub struct IdlMetadata {
|
|||
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)]
|
||||
|
@ -46,6 +48,14 @@ pub struct IdlDependency {
|
|||
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,
|
||||
|
@ -137,6 +147,8 @@ pub struct IdlEvent {
|
|||
#[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,
|
||||
|
@ -176,6 +188,7 @@ pub struct IdlTypeDef {
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[non_exhaustive]
|
||||
pub enum IdlSerialization {
|
||||
#[default]
|
||||
Borsh,
|
||||
|
@ -186,6 +199,7 @@ pub enum IdlSerialization {
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
#[non_exhaustive]
|
||||
pub enum IdlRepr {
|
||||
Rust(IdlReprModifier),
|
||||
C(IdlReprModifier),
|
||||
|
@ -264,6 +278,7 @@ pub enum IdlGenericArg {
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[non_exhaustive]
|
||||
pub enum IdlType {
|
||||
Bool,
|
||||
U8,
|
||||
|
|
|
@ -33,7 +33,7 @@ idl-build = [
|
|||
"anchor-attribute-program/idl-build",
|
||||
"anchor-derive-accounts/idl-build",
|
||||
"anchor-derive-serde/idl-build",
|
||||
"anchor-idl/build",
|
||||
"anchor-lang-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-idl` should only be included with `idl-build` feature
|
||||
anchor-idl = { path = "../idl", version = "0.29.0", optional = true }
|
||||
# `anchor-lang-idl` should only be included with `idl-build` feature
|
||||
anchor-lang-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},
|
||||
|
|
|
@ -17,7 +17,7 @@ idl-build = ["anchor-syn/idl-build"]
|
|||
interface-instructions = ["anchor-syn/interface-instructions"]
|
||||
|
||||
[dependencies]
|
||||
anchor-idl = { path = "../../../idl", version = "0.29.0" }
|
||||
anchor-lang-idl = { path = "../../../idl", version = "0.1.0" }
|
||||
anchor-syn = { path = "../../syn", version = "0.29.0" }
|
||||
anyhow = "1"
|
||||
bs58 = "0.5"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_idl::types::{
|
||||
use anchor_lang_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_idl::types::Idl;
|
||||
use anchor_lang_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_idl::types::{Idl, IdlSerialization};
|
||||
use anchor_lang_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_idl::types::Idl;
|
||||
use anchor_lang_idl::types::Idl;
|
||||
use quote::quote;
|
||||
|
||||
use super::common::gen_accounts_common;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_idl::types::{Idl, IdlType};
|
||||
use anchor_lang_idl::types::{Idl, IdlType};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
|
||||
use super::common::convert_idl_type_to_str;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_idl::types::Idl;
|
||||
use anchor_lang_idl::types::Idl;
|
||||
use heck::CamelCase;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_idl::types::Idl;
|
||||
use anchor_lang_idl::types::Idl;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
use super::common::{convert_idl_type_def_to_ts, gen_discriminator};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_idl::types::{Idl, IdlInstructionAccountItem};
|
||||
use anchor_lang_idl::types::{Idl, IdlInstructionAccountItem};
|
||||
use anchor_syn::{
|
||||
codegen::accounts::{__client_accounts, __cpi_client_accounts},
|
||||
parser::accounts,
|
||||
|
@ -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_idl::types::Idl;
|
||||
use anchor_lang_idl::types::Idl;
|
||||
use quote::quote;
|
||||
|
||||
use super::common::convert_idl_type_def_to_ts;
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
use anchor_lang_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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
@ -81,4 +80,4 @@ impl IdlAccount {
|
|||
}
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
pub use anchor_idl::{build::IdlBuild, *};
|
||||
pub use anchor_lang_idl::{build::IdlBuild, *};
|
||||
|
|
|
@ -28,6 +28,7 @@ extern crate self as anchor_lang;
|
|||
use bytemuck::{Pod, Zeroable};
|
||||
use solana_program::account_info::AccountInfo;
|
||||
use solana_program::instruction::AccountMeta;
|
||||
use solana_program::program_error::ProgramError;
|
||||
use solana_program::pubkey::Pubkey;
|
||||
use std::{collections::BTreeSet, fmt::Debug, io::Write};
|
||||
|
||||
|
@ -197,7 +198,10 @@ pub trait Lamports<'info>: AsRef<AccountInfo<'info>> {
|
|||
///
|
||||
/// See [`Lamports::sub_lamports`] for subtracting lamports.
|
||||
fn add_lamports(&self, amount: u64) -> Result<&Self> {
|
||||
**self.as_ref().try_borrow_mut_lamports()? += amount;
|
||||
**self.as_ref().try_borrow_mut_lamports()? = self
|
||||
.get_lamports()
|
||||
.checked_add(amount)
|
||||
.ok_or(ProgramError::ArithmeticOverflow)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
|
@ -215,7 +219,10 @@ pub trait Lamports<'info>: AsRef<AccountInfo<'info>> {
|
|||
///
|
||||
/// See [`Lamports::add_lamports`] for adding lamports.
|
||||
fn sub_lamports(&self, amount: u64) -> Result<&Self> {
|
||||
**self.as_ref().try_borrow_mut_lamports()? -= amount;
|
||||
**self.as_ref().try_borrow_mut_lamports()? = self
|
||||
.get_lamports()
|
||||
.checked_sub(amount)
|
||||
.ok_or(ProgramError::ArithmeticOverflow)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,14 +47,14 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
|
|||
///
|
||||
/// The `entry` function here, defines the standard entry to a Solana
|
||||
/// program, where execution begins.
|
||||
pub fn entry<'info>(program_id: &Pubkey, accounts: &'info [AccountInfo<'info>], data: &[u8]) -> anchor_lang::solana_program::entrypoint::ProgramResult {
|
||||
pub fn entry<'info>(program_id: &Pubkey, accounts: &[AccountInfo<'info>], data: &[u8]) -> anchor_lang::solana_program::entrypoint::ProgramResult {
|
||||
try_entry(program_id, accounts, data).map_err(|e| {
|
||||
e.log();
|
||||
e.into()
|
||||
})
|
||||
}
|
||||
|
||||
fn try_entry<'info>(program_id: &Pubkey, accounts: &'info [AccountInfo<'info>], data: &[u8]) -> anchor_lang::Result<()> {
|
||||
fn try_entry<'info>(program_id: &Pubkey, accounts: &[AccountInfo<'info>], data: &[u8]) -> anchor_lang::Result<()> {
|
||||
#[cfg(feature = "anchor-debug")]
|
||||
{
|
||||
msg!("anchor-debug is active");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -543,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) {
|
||||
|
|
|
@ -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),*],
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ declare_id!("Lamports11111111111111111111111111111111111");
|
|||
pub mod lamports {
|
||||
use super::*;
|
||||
|
||||
pub fn test_lamports_trait(ctx: Context<TestLamportsTrait>, amount: u64) -> Result<()> {
|
||||
pub fn transfer(ctx: Context<Transfer>, amount: u64) -> Result<()> {
|
||||
let pda = &ctx.accounts.pda;
|
||||
let signer = &ctx.accounts.signer;
|
||||
|
||||
|
@ -52,13 +52,29 @@ pub mod lamports {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Return overflow error in the case of overflow (instead of panicking)
|
||||
pub fn overflow(ctx: Context<Overflow>) -> Result<()> {
|
||||
let pda = &ctx.accounts.pda;
|
||||
|
||||
match pda.add_lamports(u64::MAX) {
|
||||
Err(e) => assert_eq!(e, ProgramError::ArithmeticOverflow.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
match pda.sub_lamports(u64::MAX) {
|
||||
Err(e) => assert_eq!(e, ProgramError::ArithmeticOverflow.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestLamportsTrait<'info> {
|
||||
pub struct Transfer<'info> {
|
||||
#[account(mut)]
|
||||
pub signer: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
init,
|
||||
payer = signer,
|
||||
|
@ -67,9 +83,14 @@ pub struct TestLamportsTrait<'info> {
|
|||
bump
|
||||
)]
|
||||
pub pda: Account<'info, LamportsPda>,
|
||||
|
||||
pub system_program: Program<'info, System>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Overflow<'info> {
|
||||
#[account(seeds = [b"lamports"], bump)]
|
||||
pub pda: Account<'info, LamportsPda>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct LamportsPda {}
|
||||
|
|
|
@ -8,16 +8,13 @@ describe("lamports", () => {
|
|||
|
||||
const program = anchor.workspace.Lamports as anchor.Program<Lamports>;
|
||||
|
||||
it("Can use the Lamports trait", async () => {
|
||||
const signer = program.provider.publicKey!;
|
||||
const [pda] = anchor.web3.PublicKey.findProgramAddressSync(
|
||||
[Buffer.from("lamports")],
|
||||
program.programId
|
||||
);
|
||||
|
||||
it("Can transfer from/to PDA", async () => {
|
||||
await program.methods
|
||||
.testLamportsTrait(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
|
||||
.accounts({ signer, pda })
|
||||
.transfer(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
|
||||
.rpc();
|
||||
});
|
||||
|
||||
it("Returns an error on overflow", async () => {
|
||||
await program.methods.overflow().rpc();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"pyth",
|
||||
"realloc",
|
||||
"spl/metadata",
|
||||
"spl/token-extensions",
|
||||
"spl/token-proxy",
|
||||
"spl/token-wrapper",
|
||||
"spl/transfer-hook",
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
token_extensions = "tKEkkQtgMXhdaz5NMTR3XbdUu215sZyHSj6Menvous1"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -t 1000000 tests/*.ts"
|
||||
|
||||
[features]
|
||||
|
||||
[test.validator]
|
||||
url = "https://api.mainnet-beta.solana.com"
|
|
@ -0,0 +1,8 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"programs/*"
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[profile.release]
|
||||
overflow-checks = true
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "token-extensions",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solana/spl-token": "^0.3.9"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "token-extensions"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
rust-version = "1.60"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "token_extensions"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../../lang", features = ["init-if-needed"] }
|
||||
anchor-spl = { path = "../../../../../spl" }
|
||||
spl-tlv-account-resolution = "0.6.3"
|
||||
spl-transfer-hook-interface = "0.6.3"
|
||||
spl-type-length-value = "0.4.3"
|
||||
spl-pod = "0.2.2"
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,180 @@
|
|||
use anchor_lang::{prelude::*, solana_program::entrypoint::ProgramResult};
|
||||
|
||||
use anchor_spl::{
|
||||
associated_token::AssociatedToken,
|
||||
token_2022::spl_token_2022::extension::{
|
||||
group_member_pointer::GroupMemberPointer, metadata_pointer::MetadataPointer,
|
||||
mint_close_authority::MintCloseAuthority, permanent_delegate::PermanentDelegate,
|
||||
transfer_hook::TransferHook,
|
||||
},
|
||||
token_interface::{
|
||||
spl_token_metadata_interface::state::TokenMetadata, token_metadata_initialize, Mint,
|
||||
Token2022, TokenAccount, TokenMetadataInitialize,
|
||||
},
|
||||
};
|
||||
use spl_pod::optional_keys::OptionalNonZeroPubkey;
|
||||
|
||||
use crate::{
|
||||
get_meta_list_size, get_mint_extensible_extension_data, get_mint_extension_data,
|
||||
update_account_lamports_to_minimum_balance, META_LIST_ACCOUNT_SEED,
|
||||
};
|
||||
|
||||
#[derive(AnchorDeserialize, AnchorSerialize)]
|
||||
pub struct CreateMintAccountArgs {
|
||||
pub name: String,
|
||||
pub symbol: String,
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(args: CreateMintAccountArgs)]
|
||||
pub struct CreateMintAccount<'info> {
|
||||
#[account(mut)]
|
||||
pub payer: Signer<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK: can be any account
|
||||
pub authority: Signer<'info>,
|
||||
#[account()]
|
||||
/// CHECK: can be any account
|
||||
pub receiver: UncheckedAccount<'info>,
|
||||
#[account(
|
||||
init,
|
||||
signer,
|
||||
payer = payer,
|
||||
mint::token_program = token_program,
|
||||
mint::decimals = 0,
|
||||
mint::authority = authority,
|
||||
mint::freeze_authority = authority,
|
||||
extensions::metadata_pointer::authority = authority,
|
||||
extensions::metadata_pointer::metadata_address = mint,
|
||||
extensions::group_member_pointer::authority = authority,
|
||||
extensions::group_member_pointer::member_address = mint,
|
||||
extensions::transfer_hook::authority = authority,
|
||||
extensions::transfer_hook::program_id = crate::ID,
|
||||
extensions::close_authority::authority = authority,
|
||||
extensions::permanent_delegate::delegate = authority,
|
||||
)]
|
||||
pub mint: Box<InterfaceAccount<'info, Mint>>,
|
||||
#[account(
|
||||
init,
|
||||
payer = payer,
|
||||
associated_token::token_program = token_program,
|
||||
associated_token::mint = mint,
|
||||
associated_token::authority = receiver,
|
||||
)]
|
||||
pub mint_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
|
||||
/// CHECK: This account's data is a buffer of TLV data
|
||||
#[account(
|
||||
init,
|
||||
space = get_meta_list_size(None),
|
||||
seeds = [META_LIST_ACCOUNT_SEED, mint.key().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
)]
|
||||
pub extra_metas_account: UncheckedAccount<'info>,
|
||||
pub system_program: Program<'info, System>,
|
||||
pub associated_token_program: Program<'info, AssociatedToken>,
|
||||
pub token_program: Program<'info, Token2022>,
|
||||
}
|
||||
|
||||
impl<'info> CreateMintAccount<'info> {
|
||||
fn initialize_token_metadata(
|
||||
&self,
|
||||
name: String,
|
||||
symbol: String,
|
||||
uri: String,
|
||||
) -> ProgramResult {
|
||||
let cpi_accounts = TokenMetadataInitialize {
|
||||
token_program_id: self.token_program.to_account_info(),
|
||||
mint: self.mint.to_account_info(),
|
||||
metadata: self.mint.to_account_info(), // metadata account is the mint, since data is stored in mint
|
||||
mint_authority: self.authority.to_account_info(),
|
||||
update_authority: self.authority.to_account_info(),
|
||||
};
|
||||
let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts);
|
||||
token_metadata_initialize(cpi_ctx, name, symbol, uri)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handler(ctx: Context<CreateMintAccount>, args: CreateMintAccountArgs) -> Result<()> {
|
||||
ctx.accounts.initialize_token_metadata(
|
||||
args.name.clone(),
|
||||
args.symbol.clone(),
|
||||
args.uri.clone(),
|
||||
)?;
|
||||
ctx.accounts.mint.reload()?;
|
||||
let mint_data = &mut ctx.accounts.mint.to_account_info();
|
||||
let metadata = get_mint_extensible_extension_data::<TokenMetadata>(mint_data)?;
|
||||
assert_eq!(metadata.mint, ctx.accounts.mint.key());
|
||||
assert_eq!(metadata.name, args.name);
|
||||
assert_eq!(metadata.symbol, args.symbol);
|
||||
assert_eq!(metadata.uri, args.uri);
|
||||
let metadata_pointer = get_mint_extension_data::<MetadataPointer>(mint_data)?;
|
||||
let mint_key: Option<Pubkey> = Some(ctx.accounts.mint.key());
|
||||
let authority_key: Option<Pubkey> = Some(ctx.accounts.authority.key());
|
||||
assert_eq!(
|
||||
metadata_pointer.metadata_address,
|
||||
OptionalNonZeroPubkey::try_from(mint_key)?
|
||||
);
|
||||
assert_eq!(
|
||||
metadata_pointer.authority,
|
||||
OptionalNonZeroPubkey::try_from(authority_key)?
|
||||
);
|
||||
let permanent_delegate = get_mint_extension_data::<PermanentDelegate>(mint_data)?;
|
||||
assert_eq!(
|
||||
permanent_delegate.delegate,
|
||||
OptionalNonZeroPubkey::try_from(authority_key)?
|
||||
);
|
||||
let close_authority = get_mint_extension_data::<MintCloseAuthority>(mint_data)?;
|
||||
assert_eq!(
|
||||
close_authority.close_authority,
|
||||
OptionalNonZeroPubkey::try_from(authority_key)?
|
||||
);
|
||||
let transfer_hook = get_mint_extension_data::<TransferHook>(mint_data)?;
|
||||
let program_id: Option<Pubkey> = Some(ctx.program_id.key());
|
||||
assert_eq!(
|
||||
transfer_hook.authority,
|
||||
OptionalNonZeroPubkey::try_from(authority_key)?
|
||||
);
|
||||
assert_eq!(
|
||||
transfer_hook.program_id,
|
||||
OptionalNonZeroPubkey::try_from(program_id)?
|
||||
);
|
||||
let group_member_pointer = get_mint_extension_data::<GroupMemberPointer>(mint_data)?;
|
||||
assert_eq!(
|
||||
group_member_pointer.authority,
|
||||
OptionalNonZeroPubkey::try_from(authority_key)?
|
||||
);
|
||||
assert_eq!(
|
||||
group_member_pointer.member_address,
|
||||
OptionalNonZeroPubkey::try_from(mint_key)?
|
||||
);
|
||||
// transfer minimum rent to mint account
|
||||
update_account_lamports_to_minimum_balance(
|
||||
ctx.accounts.mint.to_account_info(),
|
||||
ctx.accounts.payer.to_account_info(),
|
||||
ctx.accounts.system_program.to_account_info(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction()]
|
||||
pub struct CheckMintExtensionConstraints<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK: can be any account
|
||||
pub authority: Signer<'info>,
|
||||
#[account(
|
||||
extensions::metadata_pointer::authority = authority,
|
||||
extensions::metadata_pointer::metadata_address = mint,
|
||||
extensions::group_member_pointer::authority = authority,
|
||||
extensions::group_member_pointer::member_address = mint,
|
||||
extensions::transfer_hook::authority = authority,
|
||||
extensions::transfer_hook::program_id = crate::ID,
|
||||
extensions::close_authority::authority = authority,
|
||||
extensions::permanent_delegate::delegate = authority,
|
||||
)]
|
||||
pub mint: Box<InterfaceAccount<'info, Mint>>,
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//! An example of a program with token extensions enabled
|
||||
//!
|
||||
//! This program is intended to implement various token2022 extensions
|
||||
//!
|
||||
//! <https://spl.solana.com/token-2022/extensions>
|
||||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
pub mod instructions;
|
||||
pub mod utils;
|
||||
pub use instructions::*;
|
||||
pub use utils::*;
|
||||
|
||||
declare_id!("tKEkkQtgMXhdaz5NMTR3XbdUu215sZyHSj6Menvous1");
|
||||
|
||||
#[program]
|
||||
pub mod token_extensions {
|
||||
use super::*;
|
||||
|
||||
pub fn create_mint_account(
|
||||
ctx: Context<CreateMintAccount>,
|
||||
args: CreateMintAccountArgs,
|
||||
) -> Result<()> {
|
||||
instructions::handler(ctx, args)
|
||||
}
|
||||
|
||||
pub fn check_mint_extensions_constraints(
|
||||
_ctx: Context<CheckMintExtensionConstraints>,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
use anchor_lang::{
|
||||
prelude::Result,
|
||||
solana_program::{
|
||||
account_info::AccountInfo,
|
||||
instruction::{get_stack_height, TRANSACTION_LEVEL_STACK_HEIGHT},
|
||||
program::invoke,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
system_instruction::transfer,
|
||||
sysvar::Sysvar,
|
||||
},
|
||||
Lamports,
|
||||
};
|
||||
use anchor_spl::token_interface::spl_token_2022::{
|
||||
extension::{BaseStateWithExtensions, Extension, StateWithExtensions},
|
||||
solana_zk_token_sdk::zk_token_proof_instruction::Pod,
|
||||
state::Mint,
|
||||
};
|
||||
use spl_tlv_account_resolution::{account::ExtraAccountMeta, state::ExtraAccountMetaList};
|
||||
use spl_type_length_value::variable_len_pack::VariableLenPack;
|
||||
|
||||
pub const APPROVE_ACCOUNT_SEED: &[u8] = b"approve-account";
|
||||
pub const META_LIST_ACCOUNT_SEED: &[u8] = b"extra-account-metas";
|
||||
|
||||
pub fn update_account_lamports_to_minimum_balance<'info>(
|
||||
account: AccountInfo<'info>,
|
||||
payer: AccountInfo<'info>,
|
||||
system_program: AccountInfo<'info>,
|
||||
) -> Result<()> {
|
||||
let extra_lamports = Rent::get()?.minimum_balance(account.data_len()) - account.get_lamports();
|
||||
if extra_lamports > 0 {
|
||||
invoke(
|
||||
&transfer(payer.key, account.key, extra_lamports),
|
||||
&[payer, account, system_program],
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_mint_extensible_extension_data<T: Extension + VariableLenPack>(
|
||||
account: &mut AccountInfo,
|
||||
) -> Result<T> {
|
||||
let mint_data = account.data.borrow();
|
||||
let mint_with_extension = StateWithExtensions::<Mint>::unpack(&mint_data)?;
|
||||
let extension_data = mint_with_extension.get_variable_len_extension::<T>()?;
|
||||
Ok(extension_data)
|
||||
}
|
||||
|
||||
pub fn get_mint_extension_data<T: Extension + Pod>(account: &mut AccountInfo) -> Result<T> {
|
||||
let mint_data = account.data.borrow();
|
||||
let mint_with_extension = StateWithExtensions::<Mint>::unpack(&mint_data)?;
|
||||
let extension_data = *mint_with_extension.get_extension::<T>()?;
|
||||
Ok(extension_data)
|
||||
}
|
||||
|
||||
pub fn get_extra_meta_list_account_pda(mint: Pubkey) -> Pubkey {
|
||||
Pubkey::find_program_address(&[META_LIST_ACCOUNT_SEED, mint.as_ref()], &crate::id()).0
|
||||
}
|
||||
|
||||
pub fn get_approve_account_pda(mint: Pubkey) -> Pubkey {
|
||||
Pubkey::find_program_address(&[APPROVE_ACCOUNT_SEED, mint.as_ref()], &crate::id()).0
|
||||
}
|
||||
|
||||
/// Determine if we are in CPI
|
||||
pub fn hook_in_cpi() -> bool {
|
||||
let stack_height = get_stack_height();
|
||||
let tx_height = TRANSACTION_LEVEL_STACK_HEIGHT;
|
||||
let hook_height: usize = tx_height + 1;
|
||||
|
||||
stack_height > hook_height
|
||||
}
|
||||
|
||||
pub fn get_meta_list(approve_account: Option<Pubkey>) -> Vec<ExtraAccountMeta> {
|
||||
if let Some(approve_account) = approve_account {
|
||||
return vec![ExtraAccountMeta {
|
||||
discriminator: 0,
|
||||
address_config: approve_account.to_bytes(),
|
||||
is_signer: false.into(),
|
||||
is_writable: true.into(),
|
||||
}];
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
|
||||
pub fn get_meta_list_size(approve_account: Option<Pubkey>) -> usize {
|
||||
// safe because it's either 0 or 1
|
||||
ExtraAccountMetaList::size_of(get_meta_list(approve_account).len()).unwrap()
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import * as anchor from "@coral-xyz/anchor";
|
||||
import { Program } from "@coral-xyz/anchor";
|
||||
import { PublicKey, Keypair } from "@solana/web3.js";
|
||||
import { TokenExtensions } from "../target/types/token_extensions";
|
||||
import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token";
|
||||
import { it } from "node:test";
|
||||
|
||||
const TOKEN_2022_PROGRAM_ID = new anchor.web3.PublicKey(
|
||||
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
|
||||
);
|
||||
|
||||
export function associatedAddress({
|
||||
mint,
|
||||
owner,
|
||||
}: {
|
||||
mint: PublicKey;
|
||||
owner: PublicKey;
|
||||
}): PublicKey {
|
||||
return PublicKey.findProgramAddressSync(
|
||||
[owner.toBuffer(), TOKEN_2022_PROGRAM_ID.toBuffer(), mint.toBuffer()],
|
||||
ASSOCIATED_PROGRAM_ID
|
||||
)[0];
|
||||
}
|
||||
|
||||
describe("token extensions", () => {
|
||||
const provider = anchor.AnchorProvider.env();
|
||||
anchor.setProvider(provider);
|
||||
|
||||
const program = anchor.workspace.TokenExtensions as Program<TokenExtensions>;
|
||||
|
||||
const payer = Keypair.generate();
|
||||
|
||||
it("airdrop payer", async () => {
|
||||
await provider.connection.confirmTransaction(
|
||||
await provider.connection.requestAirdrop(payer.publicKey, 10000000000),
|
||||
"confirmed"
|
||||
);
|
||||
});
|
||||
|
||||
let mint = new Keypair();
|
||||
|
||||
it("Create mint account test passes", async () => {
|
||||
const [extraMetasAccount] = PublicKey.findProgramAddressSync(
|
||||
[
|
||||
anchor.utils.bytes.utf8.encode("extra-account-metas"),
|
||||
mint.publicKey.toBuffer(),
|
||||
],
|
||||
program.programId
|
||||
);
|
||||
await program.methods
|
||||
.createMintAccount({
|
||||
name: "hello",
|
||||
symbol: "hi",
|
||||
uri: "https://hi.com",
|
||||
})
|
||||
.accountsStrict({
|
||||
payer: payer.publicKey,
|
||||
authority: payer.publicKey,
|
||||
receiver: payer.publicKey,
|
||||
mint: mint.publicKey,
|
||||
mintTokenAccount: associatedAddress({
|
||||
mint: mint.publicKey,
|
||||
owner: payer.publicKey,
|
||||
}),
|
||||
extraMetasAccount: extraMetasAccount,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
|
||||
tokenProgram: TOKEN_2022_PROGRAM_ID,
|
||||
})
|
||||
.signers([mint, payer])
|
||||
.rpc();
|
||||
});
|
||||
|
||||
it("mint extension constraints test passes", async () => {
|
||||
await program.methods
|
||||
.checkMintExtensionsConstraints()
|
||||
.accountsStrict({
|
||||
authority: payer.publicKey,
|
||||
mint: mint.publicKey,
|
||||
})
|
||||
.signers([payer])
|
||||
.rpc();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai", "node"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
|
@ -191,7 +191,8 @@ pub struct ProxyCreateAssociatedTokenAccount<'info> {
|
|||
pub struct ProxyCreateMint<'info> {
|
||||
#[account(mut)]
|
||||
pub authority: Signer<'info>,
|
||||
#[account(init,
|
||||
#[account(
|
||||
init,
|
||||
mint::decimals = 9,
|
||||
mint::authority = authority,
|
||||
seeds = [authority.key().as_ref(), name.as_bytes(), b"token-proxy-mint"],
|
||||
|
|
|
@ -315,6 +315,10 @@ export const LangErrorCode = {
|
|||
// IDL instructions.
|
||||
IdlInstructionStub: 1000,
|
||||
IdlInstructionInvalidProgram: 1001,
|
||||
IdlAccountNotEmpty: 1002,
|
||||
|
||||
// Event instructions.
|
||||
EventInstructionStub: 1500,
|
||||
|
||||
// Constraints.
|
||||
ConstraintMut: 2000,
|
||||
|
@ -338,6 +342,25 @@ export const LangErrorCode = {
|
|||
ConstraintMintDecimals: 2018,
|
||||
ConstraintSpace: 2019,
|
||||
ConstraintAccountIsNone: 2020,
|
||||
ConstraintTokenTokenProgram: 2021,
|
||||
ConstraintMintTokenProgram: 2022,
|
||||
ConstraintAssociatedTokenTokenProgram: 2023,
|
||||
ConstraintMintGroupPointerExtension: 2024,
|
||||
ConstraintMintGroupPointerExtensionAuthority: 2025,
|
||||
ConstraintMintGroupPointerExtensionGroupAddress: 2026,
|
||||
ConstraintMintGroupMemberPointerExtension: 2027,
|
||||
ConstraintMintGroupMemberPointerExtensionAuthority: 2028,
|
||||
ConstraintMintGroupMemberPointerExtensionMemberAddress: 2029,
|
||||
ConstraintMintMetadataPointerExtension: 2030,
|
||||
ConstraintMintMetadataPointerExtensionAuthority: 2031,
|
||||
ConstraintMintMetadataPointerExtensionMetadataAddress: 2032,
|
||||
ConstraintMintCloseAuthorityExtension: 2033,
|
||||
ConstraintMintCloseAuthorityExtensionAuthority: 2034,
|
||||
ConstraintMintPermanentDelegateExtension: 2035,
|
||||
ConstraintMintPermanentDelegateExtensionDelegate: 2036,
|
||||
ConstraintMintTransferHookExtension: 2037,
|
||||
ConstraintMintTransferHookExtensionAuthority: 2038,
|
||||
ConstraintMintTransferHookExtensionProgramId: 2039,
|
||||
|
||||
// Require.
|
||||
RequireViolated: 2500,
|
||||
|
@ -370,6 +393,7 @@ export const LangErrorCode = {
|
|||
|
||||
// Miscellaneous
|
||||
DeclaredProgramIdMismatch: 4100,
|
||||
TryingToInitPayerAsProgramAccount: 4101,
|
||||
|
||||
// Used for APIs that shouldn't be used anymore.
|
||||
Deprecated: 5000,
|
||||
|
@ -403,6 +427,16 @@ export const LangErrorMessage = new Map([
|
|||
LangErrorCode.IdlInstructionInvalidProgram,
|
||||
"The transaction was given an invalid program for the IDL instruction",
|
||||
],
|
||||
[
|
||||
LangErrorCode.IdlAccountNotEmpty,
|
||||
"IDL account must be empty in order to resize, try closing first",
|
||||
],
|
||||
|
||||
// Event instructions.
|
||||
[
|
||||
LangErrorCode.EventInstructionStub,
|
||||
"The program was compiled without `event-cpi` feature",
|
||||
],
|
||||
|
||||
// Constraints.
|
||||
[LangErrorCode.ConstraintMut, "A mut constraint was violated"],
|
||||
|
@ -447,6 +481,82 @@ export const LangErrorMessage = new Map([
|
|||
LangErrorCode.ConstraintAccountIsNone,
|
||||
"A required account for the constraint is None",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintTokenTokenProgram,
|
||||
"A token account token program constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTokenProgram,
|
||||
"A mint token program constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintAssociatedTokenTokenProgram,
|
||||
"An associated token account token program constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupPointerExtension,
|
||||
"A group pointer extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupPointerExtensionAuthority,
|
||||
"A group pointer extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupPointerExtensionGroupAddress,
|
||||
"A group pointer extension group address constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupMemberPointerExtension,
|
||||
"A group member pointer extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupMemberPointerExtensionAuthority,
|
||||
"A group member pointer extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupMemberPointerExtensionMemberAddress,
|
||||
"A group member pointer extension group address constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintMetadataPointerExtension,
|
||||
"A metadata pointer extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintMetadataPointerExtensionAuthority,
|
||||
"A metadata pointer extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintMetadataPointerExtensionMetadataAddress,
|
||||
"A metadata pointer extension metadata address constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintCloseAuthorityExtension,
|
||||
"A close authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintCloseAuthorityExtensionAuthority,
|
||||
"A close authority extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintPermanentDelegateExtension,
|
||||
"A permanent delegate extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintPermanentDelegateExtensionDelegate,
|
||||
"A permanent delegate extension delegate constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTransferHookExtension,
|
||||
"A transfer hook extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTransferHookExtensionAuthority,
|
||||
"A transfer hook extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTransferHookExtensionProgramId,
|
||||
"A transfer hook extension transfer hook program id constraint was violated",
|
||||
],
|
||||
|
||||
// Require.
|
||||
[LangErrorCode.RequireViolated, "A require expression was violated"],
|
||||
|
@ -524,6 +634,10 @@ export const LangErrorMessage = new Map([
|
|||
LangErrorCode.DeclaredProgramIdMismatch,
|
||||
"The declared program id does not match the actual program id",
|
||||
],
|
||||
[
|
||||
LangErrorCode.TryingToInitPayerAsProgramAccount,
|
||||
"You cannot/should not initialize the payer account as a program account",
|
||||
],
|
||||
|
||||
// Deprecated
|
||||
[
|
||||
|
|
|
@ -23,6 +23,7 @@ export type IdlMetadata = {
|
|||
repository?: string;
|
||||
dependencies?: IdlDependency[];
|
||||
contact?: string;
|
||||
deployments?: IdlDeployments;
|
||||
};
|
||||
|
||||
export type IdlDependency = {
|
||||
|
@ -30,6 +31,13 @@ export type IdlDependency = {
|
|||
version: string;
|
||||
};
|
||||
|
||||
export type IdlDeployments = {
|
||||
mainnet?: string;
|
||||
testnet?: string;
|
||||
devnet?: string;
|
||||
localnet?: string;
|
||||
};
|
||||
|
||||
export type IdlInstruction = {
|
||||
name: string;
|
||||
docs?: string[];
|
||||
|
|
Loading…
Reference in New Issue