IDL generation through compilation (#2011)
Co-authored-by: acheron <acheroncrypto@gmail.com>
This commit is contained in:
parent
0225b7c0fd
commit
6ef6b79a6c
|
@ -443,6 +443,8 @@ jobs:
|
|||
path: tests/anchor-cli-account
|
||||
- cmd: cd tests/bench && anchor test --skip-lint
|
||||
path: tests/bench
|
||||
- cmd: cd tests/idl-build && ./test.sh
|
||||
path: tests/idl-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup/
|
||||
|
|
|
@ -15,6 +15,7 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
- lang: Add `get_lamports`, `add_lamports` and `sub_lamports` methods for all account types ([#2552](https://github.com/coral-xyz/anchor/pull/2552)).
|
||||
- client: Add a helper struct `DynSigner` to simplify use of `Client<C> where <C: Clone + Deref<Target = impl Signer>>` with Solana clap CLI utils that loads `Signer` as `Box<dyn Signer>` ([#2550](https://github.com/coral-xyz/anchor/pull/2550)).
|
||||
- lang: Allow CPI calls matching an interface without pinning program ID ([#2559](https://github.com/coral-xyz/anchor/pull/2559)).
|
||||
- cli, lang: Add IDL generation through compilation. `anchor build` still uses parsing method to generate IDLs, use `anchor idl build` to generate IDLs with the build method ([#2011](https://github.com/coral-xyz/anchor/pull/2011)).
|
||||
|
||||
### Fixes
|
||||
|
||||
|
@ -23,6 +24,8 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
|
||||
### Breaking
|
||||
|
||||
- syn: `idl` feature has been replaced with `idl-build`, `idl-parse` and `idl-types` features ([#2011](https://github.com/coral-xyz/anchor/pull/2011)).
|
||||
|
||||
## [0.28.0] - 2023-06-09
|
||||
|
||||
### Features
|
||||
|
|
|
@ -138,6 +138,7 @@ version = "0.28.0"
|
|||
dependencies = [
|
||||
"anchor-syn",
|
||||
"proc-macro2 1.0.60",
|
||||
"quote 1.0.28",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
|
@ -238,6 +239,17 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anchor-derive-serde"
|
||||
version = "0.28.0"
|
||||
dependencies = [
|
||||
"anchor-syn",
|
||||
"borsh-derive-internal 0.10.3",
|
||||
"proc-macro2 1.0.60",
|
||||
"quote 1.0.28",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anchor-derive-space"
|
||||
version = "0.28.0"
|
||||
|
@ -258,7 +270,9 @@ dependencies = [
|
|||
"anchor-attribute-event",
|
||||
"anchor-attribute-program",
|
||||
"anchor-derive-accounts",
|
||||
"anchor-derive-serde",
|
||||
"anchor-derive-space",
|
||||
"anchor-syn",
|
||||
"arrayref",
|
||||
"base64 0.13.1",
|
||||
"bincode",
|
||||
|
|
|
@ -19,7 +19,7 @@ default = []
|
|||
[dependencies]
|
||||
anchor-client = { path = "../client", version = "0.28.0" }
|
||||
anchor-lang = { path = "../lang", version = "0.28.0" }
|
||||
anchor-syn = { path = "../lang/syn", features = ["event-cpi", "idl", "init-if-needed"], version = "0.28.0" }
|
||||
anchor-syn = { path = "../lang/syn", features = ["event-cpi", "idl-parse", "init-if-needed"], version = "0.28.0" }
|
||||
anyhow = "1.0.32"
|
||||
base64 = "0.13.1"
|
||||
bincode = "1.3.3"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::is_hidden;
|
||||
use anchor_client::Cluster;
|
||||
use anchor_syn::idl::Idl;
|
||||
use anchor_syn::idl::types::Idl;
|
||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use heck::ToSnakeCase;
|
||||
|
|
177
cli/src/lib.rs
177
cli/src/lib.rs
|
@ -6,7 +6,10 @@ use crate::config::{
|
|||
use anchor_client::Cluster;
|
||||
use anchor_lang::idl::{IdlAccount, IdlInstruction, ERASED_AUTHORITY};
|
||||
use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize};
|
||||
use anchor_syn::idl::{EnumFields, Idl, IdlType, IdlTypeDefinitionTy};
|
||||
use anchor_syn::idl::types::{
|
||||
EnumFields, Idl, IdlConst, IdlErrorCode, IdlEvent, IdlType, IdlTypeDefinition,
|
||||
IdlTypeDefinitionTy,
|
||||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::Parser;
|
||||
use flate2::read::GzDecoder;
|
||||
|
@ -417,6 +420,11 @@ pub enum IdlCommand {
|
|||
#[clap(long)]
|
||||
no_docs: bool,
|
||||
},
|
||||
/// Generates the IDL for the program using the compilation method.
|
||||
Build {
|
||||
#[clap(long)]
|
||||
no_docs: bool,
|
||||
},
|
||||
/// Fetches an IDL for the given address from a cluster.
|
||||
/// The address can be a program, IDL account, or IDL buffer.
|
||||
Fetch {
|
||||
|
@ -1834,7 +1842,7 @@ fn extract_idl(
|
|||
let manifest_from_path = std::env::current_dir()?.join(PathBuf::from(&*file).parent().unwrap());
|
||||
let cargo = Manifest::discover_from_path(manifest_from_path)?
|
||||
.ok_or_else(|| anyhow!("Cargo.toml not found"))?;
|
||||
anchor_syn::idl::file::parse(
|
||||
anchor_syn::idl::parse::file::parse(
|
||||
&*file,
|
||||
cargo.version(),
|
||||
cfg.features.seeds,
|
||||
|
@ -1880,6 +1888,7 @@ fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> {
|
|||
out_ts,
|
||||
no_docs,
|
||||
} => idl_parse(cfg_override, file, out, out_ts, no_docs),
|
||||
IdlCommand::Build { no_docs } => idl_build(no_docs),
|
||||
IdlCommand::Fetch { address, out } => idl_fetch(cfg_override, address, out),
|
||||
}
|
||||
}
|
||||
|
@ -2225,6 +2234,165 @@ fn idl_parse(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn idl_build(no_docs: bool) -> Result<()> {
|
||||
let no_docs = if no_docs { "TRUE" } else { "FALSE" };
|
||||
|
||||
let cfg = Config::discover(&ConfigOverride::default())?.expect("Not in workspace.");
|
||||
let seeds_feature = if cfg.features.seeds { "TRUE" } else { "FALSE" };
|
||||
|
||||
let exit = std::process::Command::new("cargo")
|
||||
.args([
|
||||
"test",
|
||||
"__anchor_private_print_idl",
|
||||
"--features",
|
||||
"idl-build",
|
||||
"--",
|
||||
"--show-output",
|
||||
"--quiet",
|
||||
])
|
||||
.env("ANCHOR_IDL_GEN_NO_DOCS", no_docs)
|
||||
.env("ANCHOR_IDL_GEN_SEEDS_FEATURE", seeds_feature)
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.map_err(|e| anyhow::format_err!("{}", e.to_string()))?;
|
||||
if !exit.status.success() {
|
||||
std::process::exit(exit.status.code().unwrap_or(1));
|
||||
}
|
||||
|
||||
enum State {
|
||||
Pass,
|
||||
ConstLines(Vec<String>),
|
||||
EventLines(Vec<String>),
|
||||
ErrorsLines(Vec<String>),
|
||||
ProgramLines(Vec<String>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct IdlGenEventPrint {
|
||||
event: IdlEvent,
|
||||
defined_types: Vec<IdlTypeDefinition>,
|
||||
}
|
||||
|
||||
let mut state = State::Pass;
|
||||
|
||||
let mut events: Vec<IdlEvent> = vec![];
|
||||
let mut error_codes: Option<Vec<IdlErrorCode>> = None;
|
||||
let mut constants: Vec<IdlConst> = vec![];
|
||||
let mut defined_types: BTreeMap<String, IdlTypeDefinition> = BTreeMap::new();
|
||||
let mut curr_idl: Option<Idl> = None;
|
||||
|
||||
let mut idls: Vec<Idl> = vec![];
|
||||
|
||||
let out = String::from_utf8_lossy(&exit.stdout);
|
||||
for line in out.lines() {
|
||||
match &mut state {
|
||||
State::Pass => {
|
||||
if line == "---- IDL begin const ----" {
|
||||
state = State::ConstLines(vec![]);
|
||||
continue;
|
||||
} else if line == "---- IDL begin event ----" {
|
||||
state = State::EventLines(vec![]);
|
||||
continue;
|
||||
} else if line == "---- IDL begin errors ----" {
|
||||
state = State::ErrorsLines(vec![]);
|
||||
continue;
|
||||
} else if line == "---- IDL begin program ----" {
|
||||
state = State::ProgramLines(vec![]);
|
||||
continue;
|
||||
} else if line.starts_with("test result: ok") {
|
||||
let events = std::mem::take(&mut events);
|
||||
let error_codes = error_codes.take();
|
||||
let constants = std::mem::take(&mut constants);
|
||||
let mut defined_types = std::mem::take(&mut defined_types);
|
||||
let curr_idl = curr_idl.take();
|
||||
|
||||
let events = if !events.is_empty() {
|
||||
Some(events)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut idl = match curr_idl {
|
||||
Some(idl) => idl,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
idl.events = events;
|
||||
idl.errors = error_codes;
|
||||
idl.constants = constants;
|
||||
|
||||
idl.constants.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
idl.accounts.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
if let Some(e) = idl.events.as_mut() {
|
||||
e.sort_by(|a, b| a.name.cmp(&b.name))
|
||||
}
|
||||
|
||||
let prog_ty = std::mem::take(&mut idl.types);
|
||||
defined_types
|
||||
.extend(prog_ty.into_iter().map(|ty| (ty.path.clone().unwrap(), ty)));
|
||||
idl.types = defined_types.into_values().collect::<Vec<_>>();
|
||||
|
||||
idls.push(idl);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
State::ConstLines(lines) => {
|
||||
if line == "---- IDL end const ----" {
|
||||
let constant: IdlConst = serde_json::from_str(&lines.join("\n"))?;
|
||||
constants.push(constant);
|
||||
state = State::Pass;
|
||||
continue;
|
||||
}
|
||||
lines.push(line.to_string());
|
||||
}
|
||||
State::EventLines(lines) => {
|
||||
if line == "---- IDL end event ----" {
|
||||
let event: IdlGenEventPrint = serde_json::from_str(&lines.join("\n"))?;
|
||||
events.push(event.event);
|
||||
defined_types.extend(
|
||||
event
|
||||
.defined_types
|
||||
.into_iter()
|
||||
.map(|ty| (ty.path.clone().unwrap(), ty)),
|
||||
);
|
||||
state = State::Pass;
|
||||
continue;
|
||||
}
|
||||
lines.push(line.to_string());
|
||||
}
|
||||
State::ErrorsLines(lines) => {
|
||||
if line == "---- IDL end errors ----" {
|
||||
let errs: Vec<IdlErrorCode> = serde_json::from_str(&lines.join("\n"))?;
|
||||
error_codes = Some(errs);
|
||||
state = State::Pass;
|
||||
continue;
|
||||
}
|
||||
lines.push(line.to_string());
|
||||
}
|
||||
State::ProgramLines(lines) => {
|
||||
if line == "---- IDL end program ----" {
|
||||
let idl: Idl = serde_json::from_str(&lines.join("\n"))?;
|
||||
curr_idl = Some(idl);
|
||||
state = State::Pass;
|
||||
continue;
|
||||
}
|
||||
lines.push(line.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if idls.len() == 1 {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&idls.first().unwrap()).unwrap()
|
||||
);
|
||||
} else if idls.len() >= 2 {
|
||||
println!("{}", serde_json::to_string_pretty(&idls).unwrap());
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn idl_fetch(cfg_override: &ConfigOverride, address: Pubkey, out: Option<String>) -> Result<()> {
|
||||
let idl = fetch_idl(cfg_override, address)?;
|
||||
let out = match out {
|
||||
|
@ -2500,6 +2668,11 @@ fn deserialize_idl_type_to_json(
|
|||
|
||||
JsonValue::Array(array_data)
|
||||
}
|
||||
IdlType::GenericLenArray(_, _) => todo!("Generic length arrays are not yet supported"),
|
||||
IdlType::Generic(_) => todo!("Generic types are not yet supported"),
|
||||
IdlType::DefinedWithTypeArgs { path: _, args: _ } => {
|
||||
todo!("Defined types with type args are not yet supported")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::config::ProgramWorkspace;
|
||||
use crate::VERSION;
|
||||
use anchor_syn::idl::Idl;
|
||||
use anchor_syn::idl::types::Idl;
|
||||
use anyhow::Result;
|
||||
use heck::{ToLowerCamelCase, ToSnakeCase, ToUpperCamelCase};
|
||||
use solana_sdk::{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::config::ProgramWorkspace;
|
||||
use crate::VERSION;
|
||||
use anchor_syn::idl::Idl;
|
||||
use anchor_syn::idl::types::Idl;
|
||||
use anyhow::Result;
|
||||
use heck::{ToLowerCamelCase, ToSnakeCase, ToUpperCamelCase};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
|
|
@ -14,6 +14,16 @@ init-if-needed = ["anchor-derive-accounts/init-if-needed"]
|
|||
derive = []
|
||||
default = []
|
||||
event-cpi = ["anchor-attribute-event/event-cpi"]
|
||||
idl-build = [
|
||||
"anchor-syn/idl-build",
|
||||
"anchor-derive-accounts/idl-build",
|
||||
"anchor-derive-serde/idl-build",
|
||||
"anchor-attribute-account/idl-build",
|
||||
"anchor-attribute-constant/idl-build",
|
||||
"anchor-attribute-event/idl-build",
|
||||
"anchor-attribute-error/idl-build",
|
||||
"anchor-attribute-program/idl-build",
|
||||
]
|
||||
anchor-debug = [
|
||||
"anchor-attribute-access-control/anchor-debug",
|
||||
"anchor-attribute-account/anchor-debug",
|
||||
|
@ -33,7 +43,11 @@ anchor-attribute-error = { path = "./attribute/error", version = "0.28.0" }
|
|||
anchor-attribute-event = { path = "./attribute/event", version = "0.28.0" }
|
||||
anchor-attribute-program = { path = "./attribute/program", version = "0.28.0" }
|
||||
anchor-derive-accounts = { path = "./derive/accounts", version = "0.28.0" }
|
||||
anchor-derive-serde = { path = "./derive/serde", version = "0.28.0" }
|
||||
anchor-derive-space = { path = "./derive/space", version = "0.28.0" }
|
||||
# anchor-syn can and should only be included only for idl-build. It won't compile
|
||||
# for bpf due to proc-macro2 crate.
|
||||
anchor-syn = { path = "./syn", version = "0.28.0", optional = true }
|
||||
arrayref = "0.3"
|
||||
base64 = "0.13"
|
||||
bincode = "1"
|
||||
|
|
|
@ -12,6 +12,7 @@ edition = "2021"
|
|||
proc-macro = true
|
||||
|
||||
[features]
|
||||
idl-build = ["anchor-syn/idl-build"]
|
||||
anchor-debug = ["anchor-syn/anchor-debug"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
use anchor_syn::idl::build::*;
|
||||
use quote::quote;
|
||||
use syn::parse_macro_input;
|
||||
|
||||
|
@ -392,13 +394,26 @@ pub fn zero_copy(
|
|||
quote! {#[derive(::bytemuck::Zeroable)]}
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from(quote! {
|
||||
let ret = quote! {
|
||||
#[derive(anchor_lang::__private::ZeroCopyAccessor, Copy, Clone)]
|
||||
#repr
|
||||
#pod
|
||||
#zeroable
|
||||
#account_strct
|
||||
})
|
||||
};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
let no_docs = get_no_docs();
|
||||
let idl_gen_impl = gen_idl_gen_impl_for_struct(&account_strct, no_docs);
|
||||
return proc_macro::TokenStream::from(quote! {
|
||||
#ret
|
||||
#idl_gen_impl
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
proc_macro::TokenStream::from(ret)
|
||||
}
|
||||
|
||||
/// Defines the program's ID. This should be used at the root of all Anchor
|
||||
|
|
|
@ -12,9 +12,11 @@ edition = "2021"
|
|||
proc-macro = true
|
||||
|
||||
[features]
|
||||
idl-build = ["anchor-syn/idl-build"]
|
||||
anchor-debug = ["anchor-syn/anchor-debug"]
|
||||
|
||||
[dependencies]
|
||||
anchor-syn = { path = "../../syn", version = "0.28.0" }
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "1", features = ["full"] }
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
use {anchor_syn::idl::build::gen_idl_print_function_for_constant, quote::quote, syn};
|
||||
|
||||
/// A marker attribute used to mark const values that should be included in the
|
||||
/// generated IDL but functionally does nothing.
|
||||
#[proc_macro_attribute]
|
||||
|
@ -7,5 +10,24 @@ pub fn constant(
|
|||
_attr: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
let ts = match syn::parse(input).unwrap() {
|
||||
syn::Item::Const(item) => {
|
||||
let idl_print = gen_idl_print_function_for_constant(&item);
|
||||
quote! {
|
||||
#item
|
||||
#idl_print
|
||||
}
|
||||
}
|
||||
item => quote! {#item},
|
||||
};
|
||||
|
||||
return proc_macro::TokenStream::from(quote! {
|
||||
#ts
|
||||
});
|
||||
};
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
input
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ edition = "2021"
|
|||
proc-macro = true
|
||||
|
||||
[features]
|
||||
idl-build = ["anchor-syn/idl-build"]
|
||||
anchor-debug = ["anchor-syn/anchor-debug"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -12,6 +12,7 @@ edition = "2021"
|
|||
proc-macro = true
|
||||
|
||||
[features]
|
||||
idl-build = ["anchor-syn/idl-build"]
|
||||
anchor-debug = ["anchor-syn/anchor-debug"]
|
||||
event-cpi = ["anchor-syn/event-cpi"]
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn event(
|
|||
format!("{discriminator:?}").parse().unwrap()
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from(quote! {
|
||||
let ret = quote! {
|
||||
#[derive(anchor_lang::__private::EventIndex, AnchorSerialize, AnchorDeserialize)]
|
||||
#event_strct
|
||||
|
||||
|
@ -44,7 +44,19 @@ pub fn event(
|
|||
impl anchor_lang::Discriminator for #event_name {
|
||||
const DISCRIMINATOR: [u8; 8] = #discriminator;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
let idl_gen = anchor_syn::idl::build::gen_idl_print_function_for_event(&event_strct);
|
||||
return proc_macro::TokenStream::from(quote! {
|
||||
#ret
|
||||
#idl_gen
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
proc_macro::TokenStream::from(ret)
|
||||
}
|
||||
|
||||
// EventIndex is a marker macro. It functionally does nothing other than
|
||||
|
|
|
@ -12,6 +12,7 @@ edition = "2021"
|
|||
proc-macro = true
|
||||
|
||||
[features]
|
||||
idl-build = ["anchor-syn/idl-build"]
|
||||
anchor-debug = ["anchor-syn/anchor-debug"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -15,6 +15,7 @@ proc-macro = true
|
|||
allow-missing-optionals = ["anchor-syn/allow-missing-optionals"]
|
||||
init-if-needed = ["anchor-syn/init-if-needed"]
|
||||
default = []
|
||||
idl-build = ["anchor-syn/idl-build"]
|
||||
anchor-debug = ["anchor-syn/anchor-debug"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "anchor-derive-serde"
|
||||
version = "0.28.0"
|
||||
authors = ["Anchor Maintainers <accounts@200ms.io>"]
|
||||
repository = "https://github.com/coral-xyz/anchor"
|
||||
license = "Apache-2.0"
|
||||
description = "Anchor Derive macro for serialization and deserialization"
|
||||
rust-version = "1.60"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[features]
|
||||
idl-build = [
|
||||
"anchor-syn/idl-build",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
anchor-syn = { path = "../../syn", version = "0.28.0" }
|
||||
borsh-derive-internal = ">=0.9, <0.11"
|
||||
proc-macro2 = "1"
|
||||
syn = { version = "1", features = ["full"] }
|
||||
quote = "1"
|
|
@ -0,0 +1,82 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
use borsh_derive_internal::*;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use syn::{Ident, Item};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
use {anchor_syn::idl::build::*, quote::quote};
|
||||
|
||||
fn gen_borsh_serialize(input: TokenStream) -> TokenStream2 {
|
||||
let cratename = Ident::new("borsh", Span::call_site());
|
||||
|
||||
let item: Item = syn::parse(input).unwrap();
|
||||
let res = match item {
|
||||
Item::Struct(item) => struct_ser(&item, cratename),
|
||||
Item::Enum(item) => enum_ser(&item, cratename),
|
||||
Item::Union(item) => union_ser(&item, cratename),
|
||||
// Derive macros can only be defined on structs, enums, and unions.
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(res) => res,
|
||||
Err(err) => err.to_compile_error(),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(AnchorSerialize, attributes(borsh_skip))]
|
||||
pub fn anchor_serialize(input: TokenStream) -> TokenStream {
|
||||
#[cfg(not(feature = "idl-build"))]
|
||||
let ret = gen_borsh_serialize(input);
|
||||
#[cfg(feature = "idl-build")]
|
||||
let ret = gen_borsh_serialize(input.clone());
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
let no_docs = get_no_docs();
|
||||
|
||||
let idl_gen_impl = match syn::parse(input).unwrap() {
|
||||
Item::Struct(item) => gen_idl_gen_impl_for_struct(&item, no_docs),
|
||||
Item::Enum(item) => gen_idl_gen_impl_for_enum(item, no_docs),
|
||||
Item::Union(item) => {
|
||||
// unions are not included in the IDL - TODO print a warning
|
||||
idl_gen_impl_skeleton(quote! {None}, quote! {}, &item.ident, &item.generics)
|
||||
}
|
||||
// Derive macros can only be defined on structs, enums, and unions.
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
return TokenStream::from(quote! {
|
||||
#ret
|
||||
#idl_gen_impl
|
||||
});
|
||||
};
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
TokenStream::from(ret)
|
||||
}
|
||||
|
||||
fn gen_borsh_deserialize(input: TokenStream) -> TokenStream2 {
|
||||
let cratename = Ident::new("borsh", Span::call_site());
|
||||
|
||||
let item: Item = syn::parse(input).unwrap();
|
||||
let res = match item {
|
||||
Item::Struct(item) => struct_de(&item, cratename),
|
||||
Item::Enum(item) => enum_de(&item, cratename),
|
||||
Item::Union(item) => union_de(&item, cratename),
|
||||
// Derive macros can only be defined on structs, enums, and unions.
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(res) => res,
|
||||
Err(err) => err.to_compile_error(),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(AnchorDeserialize, attributes(borsh_skip, borsh_init))]
|
||||
pub fn borsh_deserialize(input: TokenStream) -> TokenStream {
|
||||
TokenStream::from(gen_borsh_deserialize(input))
|
||||
}
|
|
@ -54,11 +54,16 @@ pub use anchor_attribute_event::{emit, event};
|
|||
pub use anchor_attribute_event::{emit_cpi, event_cpi};
|
||||
pub use anchor_attribute_program::program;
|
||||
pub use anchor_derive_accounts::Accounts;
|
||||
pub use anchor_derive_serde::{AnchorDeserialize, AnchorSerialize};
|
||||
pub use anchor_derive_space::InitSpace;
|
||||
/// Borsh is the default serialization format for instructions and accounts.
|
||||
pub use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorSerialize};
|
||||
pub use borsh::de::BorshDeserialize as AnchorDeserialize;
|
||||
pub use borsh::ser::BorshSerialize as AnchorSerialize;
|
||||
pub use solana_program;
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
pub use anchor_syn;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, error::Error>;
|
||||
|
||||
/// A data structure of validated accounts that can be deserialized from the
|
||||
|
|
|
@ -11,7 +11,9 @@ edition = "2021"
|
|||
[features]
|
||||
allow-missing-optionals = []
|
||||
init-if-needed = []
|
||||
idl = []
|
||||
idl-build = []
|
||||
idl-parse = []
|
||||
idl-types = []
|
||||
hash = []
|
||||
default = []
|
||||
anchor-debug = []
|
||||
|
|
|
@ -62,12 +62,12 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
|
|||
if f.is_optional {
|
||||
quote! {
|
||||
#docs
|
||||
pub #name: Option<anchor_lang::solana_program::pubkey::Pubkey>
|
||||
pub #name: Option<Pubkey>
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#docs
|
||||
pub #name: anchor_lang::solana_program::pubkey::Pubkey
|
||||
pub #name: Pubkey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
|
|||
let __client_accounts_mod = __client_accounts::generate(accs);
|
||||
let __cpi_client_accounts_mod = __cpi_client_accounts::generate(accs);
|
||||
|
||||
quote! {
|
||||
let ret = quote! {
|
||||
#impl_try_accounts
|
||||
#impl_to_account_infos
|
||||
#impl_to_account_metas
|
||||
|
@ -30,7 +30,21 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
|
|||
|
||||
#__client_accounts_mod
|
||||
#__cpi_client_accounts_mod
|
||||
};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
#![allow(warnings)]
|
||||
let no_docs = crate::idl::build::get_no_docs();
|
||||
let idl_gen_impl = crate::idl::build::gen_idl_gen_impl_for_accounts_strct(&accs, no_docs);
|
||||
return quote! {
|
||||
#ret
|
||||
#idl_gen_impl
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
ret
|
||||
}
|
||||
|
||||
fn generics(accs: &AccountsStruct) -> ParsedGenerics {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::Error;
|
||||
use quote::quote;
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
use crate::idl::build::gen_idl_print_function_for_error;
|
||||
|
||||
pub fn generate(error: Error) -> proc_macro2::TokenStream {
|
||||
let error_enum = &error.raw_enum;
|
||||
let enum_name = &error.ident;
|
||||
|
@ -47,7 +50,7 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let offset = match error.args {
|
||||
let offset = match &error.args {
|
||||
None => quote! { anchor_lang::error::ERROR_CODE_OFFSET},
|
||||
Some(args) => {
|
||||
let offset = &args.offset;
|
||||
|
@ -55,7 +58,7 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream {
|
|||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
let ret = quote! {
|
||||
#[derive(std::fmt::Debug, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
#error_enum
|
||||
|
@ -96,5 +99,17 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
let idl_gen = gen_idl_print_function_for_error(&error);
|
||||
return quote! {
|
||||
#ret
|
||||
#idl_gen
|
||||
};
|
||||
};
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
ret
|
||||
}
|
||||
|
|
|
@ -21,16 +21,33 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
|
|||
let cpi = cpi::generate(program);
|
||||
let accounts = accounts::generate(program);
|
||||
|
||||
quote! {
|
||||
// TODO: remove once we allow segmented paths in `Accounts` structs.
|
||||
use self::#mod_name::*;
|
||||
#[allow(clippy::let_and_return)]
|
||||
let ret = {
|
||||
quote! {
|
||||
// TODO: remove once we allow segmented paths in `Accounts` structs.
|
||||
use self::#mod_name::*;
|
||||
|
||||
#entry
|
||||
#dispatch
|
||||
#handlers
|
||||
#user_defined_program
|
||||
#instruction
|
||||
#cpi
|
||||
#accounts
|
||||
}
|
||||
#entry
|
||||
#dispatch
|
||||
#handlers
|
||||
#user_defined_program
|
||||
#instruction
|
||||
#cpi
|
||||
#accounts
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
{
|
||||
let no_docs = crate::idl::build::get_no_docs();
|
||||
let idl_gen = crate::idl::build::gen_idl_print_function_for_program(program, no_docs);
|
||||
|
||||
return quote! {
|
||||
#ret
|
||||
#idl_gen
|
||||
};
|
||||
};
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
ret
|
||||
}
|
||||
|
|
|
@ -0,0 +1,915 @@
|
|||
use crate::{parser::docs, AccountField, AccountsStruct, Error, Program};
|
||||
use heck::MixedCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
pub use serde_json;
|
||||
use syn::{Ident, ItemEnum, ItemStruct};
|
||||
|
||||
#[inline(always)]
|
||||
fn get_module_paths() -> (TokenStream, TokenStream) {
|
||||
(
|
||||
quote!(anchor_lang::anchor_syn::idl::types),
|
||||
quote!(anchor_lang::anchor_syn::idl::build::serde_json),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_no_docs() -> bool {
|
||||
std::option_env!("ANCHOR_IDL_GEN_NO_DOCS")
|
||||
.map(|val| val == "TRUE")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_seeds_feature() -> bool {
|
||||
std::option_env!("ANCHOR_IDL_GEN_SEEDS_FEATURE")
|
||||
.map(|val| val == "TRUE")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
// Returns TokenStream for IdlType enum and the syn::TypePath for the defined
|
||||
// type if any.
|
||||
// Returns Err when the type wasn't parsed successfully.
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn idl_type_ts_from_syn_type(
|
||||
ty: &syn::Type,
|
||||
type_params: &Vec<Ident>,
|
||||
) -> Result<(TokenStream, Vec<syn::TypePath>), ()> {
|
||||
let (idl, _) = get_module_paths();
|
||||
|
||||
fn the_only_segment_is(path: &syn::TypePath, cmp: &str) -> bool {
|
||||
if path.path.segments.len() != 1 {
|
||||
return false;
|
||||
};
|
||||
return path.path.segments.first().unwrap().ident == cmp;
|
||||
}
|
||||
|
||||
// Foo<first::path, second::path> -> first::path
|
||||
fn get_first_angle_bracketed_path_arg(segment: &syn::PathSegment) -> Option<&syn::Type> {
|
||||
match &segment.arguments {
|
||||
syn::PathArguments::AngleBracketed(arguments) => match arguments.args.first() {
|
||||
Some(syn::GenericArgument::Type(ty)) => Some(ty),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
match ty {
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "bool") => {
|
||||
Ok((quote! { #idl::IdlType::Bool }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "u8") => {
|
||||
Ok((quote! { #idl::IdlType::U8 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "i8") => {
|
||||
Ok((quote! { #idl::IdlType::I8 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "u16") => {
|
||||
Ok((quote! { #idl::IdlType::U16 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "i16") => {
|
||||
Ok((quote! { #idl::IdlType::I16 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "u32") => {
|
||||
Ok((quote! { #idl::IdlType::U32 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "i32") => {
|
||||
Ok((quote! { #idl::IdlType::I32 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "f32") => {
|
||||
Ok((quote! { #idl::IdlType::F32 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "u64") => {
|
||||
Ok((quote! { #idl::IdlType::U64 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "i64") => {
|
||||
Ok((quote! { #idl::IdlType::I64 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "f64") => {
|
||||
Ok((quote! { #idl::IdlType::F64 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "u128") => {
|
||||
Ok((quote! { #idl::IdlType::U128 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "i128") => {
|
||||
Ok((quote! { #idl::IdlType::I128 }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path)
|
||||
if the_only_segment_is(path, "String") || the_only_segment_is(path, "&str") =>
|
||||
{
|
||||
Ok((quote! { #idl::IdlType::String }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "Pubkey") => {
|
||||
Ok((quote! { #idl::IdlType::PublicKey }, vec![]))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "Vec") => {
|
||||
let segment = path.path.segments.first().unwrap();
|
||||
let arg = match get_first_angle_bracketed_path_arg(segment) {
|
||||
Some(arg) => arg,
|
||||
None => unreachable!("Vec arguments can only be of AngleBracketed variant"),
|
||||
};
|
||||
match arg {
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "u8") => {
|
||||
return Ok((quote! {#idl::IdlType::Bytes}, vec![]));
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
let (inner, defined) = idl_type_ts_from_syn_type(arg, type_params)?;
|
||||
Ok((quote! { #idl::IdlType::Vec(Box::new(#inner)) }, defined))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "Option") => {
|
||||
let segment = path.path.segments.first().unwrap();
|
||||
let arg = match get_first_angle_bracketed_path_arg(segment) {
|
||||
Some(arg) => arg,
|
||||
None => unreachable!("Option arguments can only be of AngleBracketed variant"),
|
||||
};
|
||||
let (inner, defined) = idl_type_ts_from_syn_type(arg, type_params)?;
|
||||
Ok((quote! { #idl::IdlType::Option(Box::new(#inner)) }, defined))
|
||||
}
|
||||
syn::Type::Path(path) if the_only_segment_is(path, "Box") => {
|
||||
let segment = path.path.segments.first().unwrap();
|
||||
let arg = match get_first_angle_bracketed_path_arg(segment) {
|
||||
Some(arg) => arg,
|
||||
None => unreachable!("Box arguments can only be of AngleBracketed variant"),
|
||||
};
|
||||
let (ts, defined) = idl_type_ts_from_syn_type(arg, type_params)?;
|
||||
Ok((quote! { #ts }, defined))
|
||||
}
|
||||
syn::Type::Array(arr) => {
|
||||
let len = arr.len.clone();
|
||||
let len_is_generic = type_params.iter().any(|param| match len {
|
||||
syn::Expr::Path(ref path) => path.path.is_ident(param),
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let (inner, defined) = idl_type_ts_from_syn_type(&arr.elem, type_params)?;
|
||||
|
||||
if len_is_generic {
|
||||
match len {
|
||||
syn::Expr::Path(ref len) => {
|
||||
let len = len.path.get_ident().unwrap().to_string();
|
||||
Ok((
|
||||
quote! { #idl::IdlType::GenericLenArray(Box::new(#inner), #len.into()) },
|
||||
defined,
|
||||
))
|
||||
}
|
||||
_ => unreachable!("Array length can only be a generic parameter"),
|
||||
}
|
||||
} else {
|
||||
Ok((
|
||||
quote! { #idl::IdlType::Array(Box::new(#inner), #len) },
|
||||
defined,
|
||||
))
|
||||
}
|
||||
}
|
||||
syn::Type::Path(path) => {
|
||||
let is_generic_param = type_params.iter().any(|param| path.path.is_ident(param));
|
||||
|
||||
if is_generic_param {
|
||||
let generic = format!("{}", path.path.get_ident().unwrap());
|
||||
Ok((quote! { #idl::IdlType::Generic(#generic.into()) }, vec![]))
|
||||
} else {
|
||||
let mut params = vec![];
|
||||
let mut defined = vec![path.clone()];
|
||||
|
||||
if let Some(segment) = &path.path.segments.last() {
|
||||
if let syn::PathArguments::AngleBracketed(ref args) = segment.arguments {
|
||||
for arg in &args.args {
|
||||
match arg {
|
||||
syn::GenericArgument::Type(ty) => {
|
||||
let (ts, def) = idl_type_ts_from_syn_type(ty, type_params)?;
|
||||
params.push(quote! { #idl::IdlDefinedTypeArg::Type(#ts) });
|
||||
defined.extend(def);
|
||||
}
|
||||
syn::GenericArgument::Const(c) => params.push(
|
||||
quote! { #idl::IdlDefinedTypeArg::Value(format!("{}", #c))},
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !params.is_empty() {
|
||||
let params = quote! { vec![#(#params),*] };
|
||||
Ok((
|
||||
quote! { #idl::IdlType::DefinedWithTypeArgs {
|
||||
path: <#path>::__anchor_private_full_path(),
|
||||
args: #params
|
||||
} },
|
||||
defined,
|
||||
))
|
||||
} else {
|
||||
Ok((
|
||||
quote! { #idl::IdlType::Defined(<#path>::__anchor_private_full_path()) },
|
||||
vec![path.clone()],
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns TokenStream for IdlField struct and the syn::TypePath for the defined
|
||||
// type if any.
|
||||
// Returns Err when the type wasn't parsed successfully
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn idl_field_ts_from_syn_field(
|
||||
field: &syn::Field,
|
||||
no_docs: bool,
|
||||
type_params: &Vec<syn::Ident>,
|
||||
) -> Result<(TokenStream, Vec<syn::TypePath>), ()> {
|
||||
let (idl, _) = get_module_paths();
|
||||
|
||||
let name = field.ident.as_ref().unwrap().to_string().to_mixed_case();
|
||||
let docs = match docs::parse(&field.attrs) {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
let (ty, defined) = idl_type_ts_from_syn_type(&field.ty, type_params)?;
|
||||
|
||||
Ok((
|
||||
quote! {
|
||||
#idl::IdlField {
|
||||
name: #name.into(),
|
||||
docs: #docs,
|
||||
ty: #ty,
|
||||
}
|
||||
},
|
||||
defined,
|
||||
))
|
||||
}
|
||||
|
||||
// Returns TokenStream for IdlEventField struct and the syn::TypePath for the defined
|
||||
// type if any.
|
||||
// Returns Err when the type wasn't parsed successfully
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn idl_event_field_ts_from_syn_field(
|
||||
field: &syn::Field,
|
||||
) -> Result<(TokenStream, Vec<syn::TypePath>), ()> {
|
||||
let (idl, _) = get_module_paths();
|
||||
|
||||
let name = field.ident.as_ref().unwrap().to_string().to_mixed_case();
|
||||
let (ty, defined) = idl_type_ts_from_syn_type(&field.ty, &vec![])?;
|
||||
|
||||
let index: bool = field
|
||||
.attrs
|
||||
.get(0)
|
||||
.and_then(|attr| attr.path.segments.first())
|
||||
.map(|segment| segment.ident == "index")
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok((
|
||||
quote! {
|
||||
#idl::IdlEventField {
|
||||
name: #name.into(),
|
||||
ty: #ty,
|
||||
index: #index,
|
||||
}
|
||||
},
|
||||
defined,
|
||||
))
|
||||
}
|
||||
|
||||
// Returns TokenStream for IdlTypeDefinitionTy::Struct and Vec<&syn::TypePath>
|
||||
// for the defined types if any.
|
||||
// Returns Err if any of the fields weren't parsed successfully.
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn idl_type_definition_ts_from_syn_struct(
|
||||
item_strct: &syn::ItemStruct,
|
||||
no_docs: bool,
|
||||
) -> Result<(TokenStream, Vec<syn::TypePath>), ()> {
|
||||
let (idl, _) = get_module_paths();
|
||||
|
||||
let name = item_strct.ident.to_string();
|
||||
let docs = match docs::parse(&item_strct.attrs) {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
|
||||
let type_params = item_strct
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|p| match p {
|
||||
syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
|
||||
syn::GenericParam::Const(c) => Some(c.ident.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let (fields, defined): (Vec<TokenStream>, Vec<Vec<syn::TypePath>>) = match &item_strct.fields {
|
||||
syn::Fields::Named(fields) => fields
|
||||
.named
|
||||
.iter()
|
||||
.map(|f: &syn::Field| idl_field_ts_from_syn_field(f, no_docs, &type_params))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>(),
|
||||
_ => return Err(()),
|
||||
};
|
||||
let defined = defined
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<syn::TypePath>>();
|
||||
|
||||
let generics = if !type_params.is_empty() {
|
||||
let g: Vec<String> = type_params.iter().map(|id| id.to_string()).collect();
|
||||
quote! { Some(vec![#(#g.into()),*]) }
|
||||
} else {
|
||||
quote! { None }
|
||||
};
|
||||
|
||||
Ok((
|
||||
quote! {
|
||||
#idl::IdlTypeDefinition {
|
||||
name: #name.into(),
|
||||
path: Some(Self::__anchor_private_full_path()),
|
||||
generics: #generics,
|
||||
docs: #docs,
|
||||
ty: #idl::IdlTypeDefinitionTy::Struct{
|
||||
fields: vec![
|
||||
#(#fields),*
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
defined,
|
||||
))
|
||||
}
|
||||
|
||||
// Returns TokenStream for IdlTypeDefinitionTy::Enum and the Vec<&syn::TypePath>
|
||||
// for the defined types if any.
|
||||
// Returns Err if any of the fields didn't parse successfully.
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn idl_type_definition_ts_from_syn_enum(
|
||||
enum_item: &syn::ItemEnum,
|
||||
no_docs: bool,
|
||||
) -> Result<(TokenStream, Vec<syn::TypePath>), ()> {
|
||||
let (idl, _) = get_module_paths();
|
||||
|
||||
let name = enum_item.ident.to_string();
|
||||
let docs = match docs::parse(&enum_item.attrs) {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
|
||||
let type_params = enum_item
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|p| match p {
|
||||
syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
|
||||
syn::GenericParam::Const(c) => Some(c.ident.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (variants, defined): (Vec<TokenStream>, Vec<Vec<syn::TypePath>>) = enum_item.variants.iter().map(|variant: &syn::Variant| {
|
||||
let name = variant.ident.to_string();
|
||||
let (fields, defined): (TokenStream, Vec<syn::TypePath>) = match &variant.fields {
|
||||
syn::Fields::Unit => (quote!{None}, vec![]),
|
||||
syn::Fields::Unnamed(fields) => {
|
||||
let (types, defined) = fields.unnamed
|
||||
.iter()
|
||||
.map(|f| idl_type_ts_from_syn_type(&f.ty, &type_params))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.unzip::<TokenStream, Vec<syn::TypePath>, Vec<TokenStream>, Vec<Vec<syn::TypePath>>>();
|
||||
let defined = defined
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(quote!{ Some(#idl::EnumFields::Tuple(vec![#(#types),*]))}, defined)
|
||||
}
|
||||
syn::Fields::Named(fields) => {
|
||||
let (fields, defined) = fields.named
|
||||
.iter()
|
||||
.map(|f| idl_field_ts_from_syn_field(f, no_docs, &type_params))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.unzip::<TokenStream, Vec<syn::TypePath>, Vec<TokenStream>, Vec<Vec<syn::TypePath>>>();
|
||||
let defined = defined
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(quote!{ Some(#idl::EnumFields::Named(vec![#(#fields),*]))}, defined)
|
||||
}
|
||||
};
|
||||
|
||||
Ok((quote!{ #idl::IdlEnumVariant{ name: #name.into(), fields: #fields }}, defined))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.unzip::<TokenStream, Vec<syn::TypePath>, Vec<TokenStream>, Vec<Vec<syn::TypePath>>>();
|
||||
|
||||
let defined = defined
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<syn::TypePath>>();
|
||||
|
||||
let generics = if !type_params.is_empty() {
|
||||
let g: Vec<String> = type_params.iter().map(|id| id.to_string()).collect();
|
||||
quote! { Some(vec![#(#g.into()),*]) }
|
||||
} else {
|
||||
quote! { None }
|
||||
};
|
||||
|
||||
Ok((
|
||||
quote! {
|
||||
#idl::IdlTypeDefinition {
|
||||
name: #name.into(),
|
||||
path: Some(Self::__anchor_private_full_path()),
|
||||
generics: #generics,
|
||||
docs: #docs,
|
||||
ty: #idl::IdlTypeDefinitionTy::Enum{
|
||||
variants: vec![
|
||||
#(#variants),*
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
defined,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn idl_gen_impl_skeleton(
|
||||
idl_type_definition_ts: TokenStream,
|
||||
insert_defined_ts: TokenStream,
|
||||
ident: &Ident,
|
||||
input_generics: &syn::Generics,
|
||||
) -> TokenStream {
|
||||
let (idl, _) = get_module_paths();
|
||||
let name = ident.to_string();
|
||||
let (impl_generics, ty_generics, where_clause) = input_generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
pub fn __anchor_private_full_path() -> String {
|
||||
format!("{}::{}", std::module_path!(), #name)
|
||||
}
|
||||
|
||||
pub fn __anchor_private_gen_idl_type() -> Option<#idl::IdlTypeDefinition> {
|
||||
#idl_type_definition_ts
|
||||
}
|
||||
|
||||
pub fn __anchor_private_insert_idl_defined(
|
||||
defined_types: &mut std::collections::HashMap<String, #idl::IdlTypeDefinition>
|
||||
) {
|
||||
#insert_defined_ts
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generates the IDL generation impl for for a struct
|
||||
pub fn gen_idl_gen_impl_for_struct(strct: &ItemStruct, no_docs: bool) -> TokenStream {
|
||||
let idl_type_definition_ts: TokenStream;
|
||||
let insert_defined_ts: TokenStream;
|
||||
|
||||
if let Ok((ts, defined)) = idl_type_definition_ts_from_syn_struct(strct, no_docs) {
|
||||
idl_type_definition_ts = quote! {Some(#ts)};
|
||||
insert_defined_ts = quote! {
|
||||
#({
|
||||
<#defined>::__anchor_private_insert_idl_defined(defined_types);
|
||||
|
||||
let path = <#defined>::__anchor_private_full_path();
|
||||
<#defined>::__anchor_private_gen_idl_type()
|
||||
.and_then(|ty| defined_types.insert(path, ty));
|
||||
});*
|
||||
};
|
||||
} else {
|
||||
idl_type_definition_ts = quote! {None};
|
||||
insert_defined_ts = quote! {};
|
||||
}
|
||||
|
||||
let ident = &strct.ident;
|
||||
let input_generics = &strct.generics;
|
||||
|
||||
idl_gen_impl_skeleton(
|
||||
idl_type_definition_ts,
|
||||
insert_defined_ts,
|
||||
ident,
|
||||
input_generics,
|
||||
)
|
||||
}
|
||||
|
||||
// generates the IDL generation impl for for an enum
|
||||
pub fn gen_idl_gen_impl_for_enum(enm: ItemEnum, no_docs: bool) -> TokenStream {
|
||||
let idl_type_definition_ts: TokenStream;
|
||||
let insert_defined_ts: TokenStream;
|
||||
|
||||
if let Ok((ts, defined)) = idl_type_definition_ts_from_syn_enum(&enm, no_docs) {
|
||||
idl_type_definition_ts = quote! {Some(#ts)};
|
||||
insert_defined_ts = quote! {
|
||||
#({
|
||||
<#defined>::__anchor_private_insert_idl_defined(defined_types);
|
||||
|
||||
let path = <#defined>::__anchor_private_full_path();
|
||||
<#defined>::__anchor_private_gen_idl_type()
|
||||
.and_then(|ty| defined_types.insert(path, ty));
|
||||
});*
|
||||
};
|
||||
} else {
|
||||
idl_type_definition_ts = quote! {None};
|
||||
insert_defined_ts = quote! {};
|
||||
}
|
||||
|
||||
let ident = &enm.ident;
|
||||
let input_generics = &enm.generics;
|
||||
|
||||
idl_gen_impl_skeleton(
|
||||
idl_type_definition_ts,
|
||||
insert_defined_ts,
|
||||
ident,
|
||||
input_generics,
|
||||
)
|
||||
}
|
||||
|
||||
// generates the IDL generation impl for for an event
|
||||
pub fn gen_idl_gen_impl_for_event(event_strct: &ItemStruct) -> TokenStream {
|
||||
fn parse_fields(
|
||||
fields: &syn::FieldsNamed,
|
||||
) -> Result<(Vec<TokenStream>, Vec<syn::TypePath>), ()> {
|
||||
let (fields, defined) = fields
|
||||
.named
|
||||
.iter()
|
||||
.map(idl_event_field_ts_from_syn_field)
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
let defined = defined
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<syn::TypePath>>();
|
||||
|
||||
Ok((fields, defined))
|
||||
}
|
||||
|
||||
let res = match &event_strct.fields {
|
||||
syn::Fields::Named(fields) => parse_fields(fields),
|
||||
_ => Err(()),
|
||||
};
|
||||
|
||||
let (idl, _) = get_module_paths();
|
||||
let name = event_strct.ident.to_string();
|
||||
|
||||
let (ret_ts, types_ts) = match res {
|
||||
Ok((fields, defined)) => {
|
||||
let ret_ts = quote! {
|
||||
Some(
|
||||
#idl::IdlEvent {
|
||||
name: #name.into(),
|
||||
fields: vec![#(#fields),*],
|
||||
}
|
||||
)
|
||||
};
|
||||
let types_ts = quote! {
|
||||
#({
|
||||
<#defined>::__anchor_private_insert_idl_defined(defined_types);
|
||||
|
||||
let path = <#defined>::__anchor_private_full_path();
|
||||
<#defined>::__anchor_private_gen_idl_type()
|
||||
.and_then(|ty| defined_types.insert(path, ty));
|
||||
});*
|
||||
};
|
||||
(ret_ts, types_ts)
|
||||
}
|
||||
Err(()) => (quote! { None }, quote! {}),
|
||||
};
|
||||
|
||||
let ident = &event_strct.ident;
|
||||
let input_generics = &event_strct.generics;
|
||||
let (impl_generics, ty_generics, where_clause) = input_generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
pub fn __anchor_private_gen_idl_event(
|
||||
defined_types: &mut std::collections::HashMap<String, #idl::IdlTypeDefinition>,
|
||||
) -> Option<#idl::IdlEvent> {
|
||||
#types_ts
|
||||
#ret_ts
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generates the IDL generation impl for the Accounts struct
|
||||
pub fn gen_idl_gen_impl_for_accounts_strct(
|
||||
accs_strct: &AccountsStruct,
|
||||
no_docs: bool,
|
||||
) -> TokenStream {
|
||||
let (idl, _) = get_module_paths();
|
||||
|
||||
let ident = &accs_strct.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = accs_strct.generics.split_for_impl();
|
||||
|
||||
let (accounts, acc_types): (Vec<TokenStream>, Vec<Option<&syn::TypePath>>) = accs_strct
|
||||
.fields
|
||||
.iter()
|
||||
.map(|acc: &AccountField| match acc {
|
||||
AccountField::CompositeField(comp_f) => {
|
||||
let ty = if let syn::Type::Path(path) = &comp_f.raw_field.ty {
|
||||
// some::path::Foo<'info> -> some::path::Foo
|
||||
let mut res = syn::Path {
|
||||
leading_colon: path.path.leading_colon,
|
||||
segments: syn::punctuated::Punctuated::new(),
|
||||
};
|
||||
for segment in &path.path.segments {
|
||||
let s = syn::PathSegment {
|
||||
ident: segment.ident.clone(),
|
||||
arguments: syn::PathArguments::None,
|
||||
};
|
||||
res.segments.push(s);
|
||||
};
|
||||
res
|
||||
} else {
|
||||
panic!("expecting path")
|
||||
};
|
||||
let name = comp_f.ident.to_string().to_mixed_case();
|
||||
(quote!{
|
||||
#idl::IdlAccountItem::IdlAccounts(#idl::IdlAccounts {
|
||||
name: #name.into(),
|
||||
accounts: <#ty>::__anchor_private_gen_idl_accounts(accounts, defined_types),
|
||||
})
|
||||
}, None)
|
||||
}
|
||||
AccountField::Field(acc) => {
|
||||
let name = acc.ident.to_string().to_mixed_case();
|
||||
let is_mut = acc.constraints.is_mutable();
|
||||
let is_signer = match acc.ty {
|
||||
crate::Ty::Signer => true,
|
||||
_ => acc.constraints.is_signer()
|
||||
};
|
||||
let is_optional = if acc.is_optional { quote!{Some(true)} } else { quote!{None} };
|
||||
let docs = match &acc.docs {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
let pda = quote!{None}; // TODO
|
||||
let relations = super::parse::relations::parse(acc, get_seeds_feature());
|
||||
|
||||
let acc_type_path = match &acc.ty {
|
||||
crate::Ty::Account(ty) => Some(&ty.account_type_path),
|
||||
crate::Ty::AccountLoader(ty) => Some(&ty.account_type_path),
|
||||
crate::Ty::InterfaceAccount(ty) => Some(&ty.account_type_path),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
(quote!{
|
||||
#idl::IdlAccountItem::IdlAccount(#idl::IdlAccount{
|
||||
name: #name.into(),
|
||||
is_mut: #is_mut,
|
||||
is_signer: #is_signer,
|
||||
is_optional: #is_optional,
|
||||
docs: #docs,
|
||||
pda: #pda,
|
||||
relations: vec![#(#relations.into()),*],
|
||||
})
|
||||
}, acc_type_path)
|
||||
}
|
||||
})
|
||||
.unzip::<TokenStream, Option<&syn::TypePath>, Vec<TokenStream>, Vec<Option<&syn::TypePath>>>();
|
||||
let acc_types = acc_types
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<&syn::TypePath>>();
|
||||
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
pub fn __anchor_private_gen_idl_accounts(
|
||||
accounts: &mut std::collections::HashMap<String, #idl::IdlTypeDefinition>,
|
||||
defined_types: &mut std::collections::HashMap<String, #idl::IdlTypeDefinition>,
|
||||
) -> Vec<#idl::IdlAccountItem> {
|
||||
#({
|
||||
<#acc_types>::__anchor_private_insert_idl_defined(defined_types);
|
||||
|
||||
let path = <#acc_types>::__anchor_private_full_path();
|
||||
<#acc_types>::__anchor_private_gen_idl_type()
|
||||
.and_then(|ty| accounts.insert(path, ty));
|
||||
|
||||
});*
|
||||
|
||||
vec![#(#accounts),*]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generates the IDL generation print function for the program module
|
||||
pub fn gen_idl_print_function_for_program(program: &Program, no_docs: bool) -> TokenStream {
|
||||
let (idl, serde_json) = get_module_paths();
|
||||
|
||||
let (instructions, defined) = program
|
||||
.ixs
|
||||
.iter()
|
||||
.flat_map(|ix| -> Result<_, ()> {
|
||||
let name = ix.ident.to_string().to_mixed_case();
|
||||
let docs = match &ix.docs {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
let ctx_ident = &ix.anchor_ident;
|
||||
|
||||
let (args, mut defined) = ix
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let arg_name = arg.name.to_string().to_mixed_case();
|
||||
let docs = match docs::parse(&arg.raw_arg.attrs) {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
let (ty, defined) = idl_type_ts_from_syn_type(&arg.raw_arg.ty, &vec![])?;
|
||||
|
||||
Ok((quote! {
|
||||
#idl::IdlField {
|
||||
name: #arg_name.into(),
|
||||
docs: #docs,
|
||||
ty: #ty,
|
||||
}
|
||||
}, defined))
|
||||
})
|
||||
.collect::<Result<Vec<_>, ()>>()?
|
||||
.into_iter()
|
||||
.unzip::<TokenStream, Vec<syn::TypePath>, Vec<TokenStream>, Vec<Vec<syn::TypePath>>>();
|
||||
|
||||
let returns = match idl_type_ts_from_syn_type(&ix.returns.ty, &vec![]) {
|
||||
Ok((ty, def)) => {
|
||||
defined.push(def);
|
||||
quote!{ Some(#ty) }
|
||||
},
|
||||
Err(()) => quote!{ None }
|
||||
};
|
||||
|
||||
Ok((quote! {
|
||||
#idl::IdlInstruction {
|
||||
name: #name.into(),
|
||||
docs: #docs,
|
||||
accounts: #ctx_ident::__anchor_private_gen_idl_accounts(
|
||||
&mut accounts,
|
||||
&mut defined_types,
|
||||
),
|
||||
args: vec![#(#args),*],
|
||||
returns: #returns,
|
||||
}
|
||||
}, defined))
|
||||
})
|
||||
.unzip::<TokenStream, Vec<Vec<syn::TypePath>>, Vec<TokenStream>, Vec<Vec<Vec<syn::TypePath>>>>();
|
||||
let defined = defined
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.collect::<Vec<syn::TypePath>>();
|
||||
|
||||
let name = program.name.to_string();
|
||||
let docs = match &program.docs {
|
||||
Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
|
||||
_ => quote! {None},
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[test]
|
||||
pub fn __anchor_private_print_idl_program() {
|
||||
let mut accounts: std::collections::HashMap<String, #idl::IdlTypeDefinition> =
|
||||
std::collections::HashMap::new();
|
||||
let mut defined_types: std::collections::HashMap<String, #idl::IdlTypeDefinition> =
|
||||
std::collections::HashMap::new();
|
||||
|
||||
#({
|
||||
<#defined>::__anchor_private_insert_idl_defined(&mut defined_types);
|
||||
|
||||
let path = <#defined>::__anchor_private_full_path();
|
||||
<#defined>::__anchor_private_gen_idl_type()
|
||||
.and_then(|ty| defined_types.insert(path, ty));
|
||||
});*
|
||||
|
||||
let instructions = vec![#(#instructions),*];
|
||||
|
||||
let idl = #idl::Idl {
|
||||
version: env!("CARGO_PKG_VERSION").into(),
|
||||
name: #name.into(),
|
||||
docs: #docs,
|
||||
constants: vec![],
|
||||
instructions,
|
||||
accounts: accounts.into_values().collect(),
|
||||
types: defined_types.into_values().collect(),
|
||||
events: None,
|
||||
errors: None,
|
||||
metadata: None,
|
||||
};
|
||||
|
||||
println!("---- IDL begin program ----");
|
||||
println!("{}", #serde_json::to_string_pretty(&idl).unwrap());
|
||||
println!("---- IDL end program ----");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_idl_print_function_for_event(event: &ItemStruct) -> TokenStream {
|
||||
let (idl, serde_json) = get_module_paths();
|
||||
|
||||
let ident = &event.ident;
|
||||
let fn_name = format_ident!("__anchor_private_print_idl_event_{}", ident.to_string());
|
||||
let impl_gen = gen_idl_gen_impl_for_event(event);
|
||||
|
||||
quote! {
|
||||
#impl_gen
|
||||
|
||||
#[test]
|
||||
pub fn #fn_name() {
|
||||
let mut defined_types: std::collections::HashMap<String, #idl::IdlTypeDefinition> = std::collections::HashMap::new();
|
||||
let event = #ident::__anchor_private_gen_idl_event(&mut defined_types);
|
||||
|
||||
if let Some(event) = event {
|
||||
let json = #serde_json::json!({
|
||||
"event": event,
|
||||
"defined_types": defined_types.into_values().collect::<Vec<#idl::IdlTypeDefinition>>()
|
||||
});
|
||||
|
||||
println!("---- IDL begin event ----");
|
||||
println!("{}", #serde_json::to_string_pretty(&json).unwrap());
|
||||
println!("---- IDL end event ----");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_idl_print_function_for_constant(item: &syn::ItemConst) -> TokenStream {
|
||||
let fn_name = format_ident!(
|
||||
"__anchor_private_print_idl_const_{}",
|
||||
item.ident.to_string()
|
||||
);
|
||||
let (idl, serde_json) = get_module_paths();
|
||||
|
||||
let name = item.ident.to_string();
|
||||
let expr = &item.expr;
|
||||
|
||||
let impl_ts = match idl_type_ts_from_syn_type(&item.ty, &vec![]) {
|
||||
Ok((ty, _)) => quote! {
|
||||
let value = format!("{}", #expr);
|
||||
|
||||
let idl = #idl::IdlConst {
|
||||
name: #name.into(),
|
||||
ty: #ty,
|
||||
value,
|
||||
};
|
||||
|
||||
println!("---- IDL begin const ----");
|
||||
println!("{}", #serde_json::to_string_pretty(&idl).unwrap());
|
||||
println!("---- IDL end const ----");
|
||||
},
|
||||
Err(()) => quote! {},
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[test]
|
||||
pub fn #fn_name() {
|
||||
#impl_ts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_idl_print_function_for_error(error: &Error) -> TokenStream {
|
||||
let fn_name = format_ident!(
|
||||
"__anchor_private_print_idl_error_{}",
|
||||
error.ident.to_string()
|
||||
);
|
||||
let (idl, serde_json) = get_module_paths();
|
||||
|
||||
let error_codes = error
|
||||
.codes
|
||||
.iter()
|
||||
.map(|code| {
|
||||
let id = code.id;
|
||||
let name = code.ident.to_string();
|
||||
|
||||
let msg = match code.msg.clone() {
|
||||
Some(msg) => quote! { Some(#msg.to_string()) },
|
||||
None => quote! { None },
|
||||
};
|
||||
|
||||
quote! {
|
||||
#idl::IdlErrorCode {
|
||||
code: anchor_lang::error::ERROR_CODE_OFFSET + #id,
|
||||
name: #name.into(),
|
||||
msg: #msg,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<TokenStream>>();
|
||||
|
||||
quote! {
|
||||
#[test]
|
||||
pub fn #fn_name() {
|
||||
let errors = vec![#(#error_codes),*];
|
||||
|
||||
println!("---- IDL begin errors ----");
|
||||
println!("{}", #serde_json::to_string_pretty(&errors).unwrap());
|
||||
println!("---- IDL end errors ----");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,330 +1,6 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
pub mod file;
|
||||
pub mod pda;
|
||||
pub mod relations;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Idl {
|
||||
pub version: String,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub constants: Vec<IdlConst>,
|
||||
pub instructions: Vec<IdlInstruction>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub accounts: Vec<IdlTypeDefinition>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub types: Vec<IdlTypeDefinition>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub events: Option<Vec<IdlEvent>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub errors: Option<Vec<IdlErrorCode>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub metadata: Option<JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlConst {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlState {
|
||||
#[serde(rename = "struct")]
|
||||
pub strct: IdlTypeDefinition,
|
||||
pub methods: Vec<IdlInstruction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlInstruction {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
pub accounts: Vec<IdlAccountItem>,
|
||||
pub args: Vec<IdlField>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub returns: Option<IdlType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlAccounts {
|
||||
pub name: String,
|
||||
pub accounts: Vec<IdlAccountItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum IdlAccountItem {
|
||||
IdlAccount(IdlAccount),
|
||||
IdlAccounts(IdlAccounts),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlAccount {
|
||||
pub name: String,
|
||||
pub is_mut: bool,
|
||||
pub is_signer: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_optional: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub pda: Option<IdlPda>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub relations: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlPda {
|
||||
pub seeds: Vec<IdlSeed>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub program_id: Option<IdlSeed>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase", tag = "kind")]
|
||||
pub enum IdlSeed {
|
||||
Const(IdlSeedConst),
|
||||
Arg(IdlSeedArg),
|
||||
Account(IdlSeedAccount),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlSeedAccount {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
// account_ty points to the entry in the "accounts" section.
|
||||
// Some only if the `Account<T>` type is used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub account: Option<String>,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlSeedArg {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlSeedConst {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub value: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlField {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEvent {
|
||||
pub name: String,
|
||||
pub fields: Vec<IdlEventField>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEventField {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub index: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlTypeDefinition {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlTypeDefinitionTy,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "lowercase", tag = "kind")]
|
||||
pub enum IdlTypeDefinitionTy {
|
||||
Struct { fields: Vec<IdlField> },
|
||||
Enum { variants: Vec<IdlEnumVariant> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEnumVariant {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub fields: Option<EnumFields>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum EnumFields {
|
||||
Named(Vec<IdlField>),
|
||||
Tuple(Vec<IdlType>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum IdlType {
|
||||
Bool,
|
||||
U8,
|
||||
I8,
|
||||
U16,
|
||||
I16,
|
||||
U32,
|
||||
I32,
|
||||
F32,
|
||||
U64,
|
||||
I64,
|
||||
F64,
|
||||
U128,
|
||||
I128,
|
||||
U256,
|
||||
I256,
|
||||
Bytes,
|
||||
String,
|
||||
PublicKey,
|
||||
Defined(String),
|
||||
Option(Box<IdlType>),
|
||||
Vec(Box<IdlType>),
|
||||
Array(Box<IdlType>, usize),
|
||||
}
|
||||
|
||||
impl std::str::FromStr for IdlType {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut s = s.to_string();
|
||||
fn array_from_str(inner: &str) -> IdlType {
|
||||
match inner.strip_suffix(']') {
|
||||
None => {
|
||||
let (raw_type, raw_length) = inner.rsplit_once(';').unwrap();
|
||||
let ty = IdlType::from_str(raw_type).unwrap();
|
||||
let len = raw_length.replace('_', "").parse::<usize>().unwrap();
|
||||
IdlType::Array(Box::new(ty), len)
|
||||
}
|
||||
Some(nested_inner) => array_from_str(&nested_inner[1..]),
|
||||
}
|
||||
}
|
||||
s.retain(|c| !c.is_whitespace());
|
||||
|
||||
let r = match s.as_str() {
|
||||
"bool" => IdlType::Bool,
|
||||
"u8" => IdlType::U8,
|
||||
"i8" => IdlType::I8,
|
||||
"u16" => IdlType::U16,
|
||||
"i16" => IdlType::I16,
|
||||
"u32" => IdlType::U32,
|
||||
"i32" => IdlType::I32,
|
||||
"f32" => IdlType::F32,
|
||||
"u64" => IdlType::U64,
|
||||
"i64" => IdlType::I64,
|
||||
"f64" => IdlType::F64,
|
||||
"u128" => IdlType::U128,
|
||||
"i128" => IdlType::I128,
|
||||
"u256" => IdlType::U256,
|
||||
"i256" => IdlType::I256,
|
||||
"Vec<u8>" => IdlType::Bytes,
|
||||
"String" | "&str" | "&'staticstr" => IdlType::String,
|
||||
"Pubkey" => IdlType::PublicKey,
|
||||
_ => match s.to_string().strip_prefix("Option<") {
|
||||
None => match s.to_string().strip_prefix("Vec<") {
|
||||
None => {
|
||||
if s.to_string().starts_with('[') {
|
||||
array_from_str(&s)
|
||||
} else {
|
||||
IdlType::Defined(s.to_string())
|
||||
}
|
||||
}
|
||||
Some(inner) => {
|
||||
let inner_ty = Self::from_str(
|
||||
inner
|
||||
.strip_suffix('>')
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid option"))?,
|
||||
)?;
|
||||
IdlType::Vec(Box::new(inner_ty))
|
||||
}
|
||||
},
|
||||
Some(inner) => {
|
||||
let inner_ty = Self::from_str(
|
||||
inner
|
||||
.strip_suffix('>')
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid option"))?,
|
||||
)?;
|
||||
IdlType::Option(Box::new(inner_ty))
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct IdlErrorCode {
|
||||
pub code: u32,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub msg: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::idl::IdlType;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn multidimensional_array() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("[[u8;16];32]").unwrap(),
|
||||
IdlType::Array(Box::new(IdlType::Array(Box::new(IdlType::U8), 16)), 32)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("[Pubkey;16]").unwrap(),
|
||||
IdlType::Array(Box::new(IdlType::PublicKey), 16)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_with_underscored_length() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("[u8;50_000]").unwrap(),
|
||||
IdlType::Array(Box::new(IdlType::U8), 50000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Option<bool>").unwrap(),
|
||||
IdlType::Option(Box::new(IdlType::Bool))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Vec<bool>").unwrap(),
|
||||
IdlType::Vec(Box::new(IdlType::Bool))
|
||||
)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "idl-build")]
|
||||
pub mod build;
|
||||
#[cfg(any(feature = "idl-parse", feature = "idl-build"))]
|
||||
pub mod parse;
|
||||
#[cfg(any(feature = "idl-types", feature = "idl-build", feature = "idl-parse"))]
|
||||
pub mod types;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::idl::*;
|
||||
use crate::idl::types::*;
|
||||
use crate::parser::context::CrateContext;
|
||||
use crate::parser::{self, accounts, docs, error, program};
|
||||
use crate::Ty;
|
||||
|
@ -13,6 +13,8 @@ use syn::{
|
|||
Lit::{Byte, ByteStr},
|
||||
};
|
||||
|
||||
use super::relations;
|
||||
|
||||
const DERIVE_NAME: &str = "Accounts";
|
||||
// TODO: share this with `anchor_lang` crate.
|
||||
const ERROR_CODE_OFFSET: u32 = 6000;
|
||||
|
@ -346,6 +348,8 @@ fn parse_ty_defs(ctx: &CrateContext, no_docs: bool) -> Result<Vec<IdlTypeDefinit
|
|||
|
||||
Some(fields.map(|fields| IdlTypeDefinition {
|
||||
name,
|
||||
path: None,
|
||||
generics: None,
|
||||
docs: doc,
|
||||
ty: IdlTypeDefinitionTy::Struct { fields },
|
||||
}))
|
||||
|
@ -404,6 +408,8 @@ fn parse_ty_defs(ctx: &CrateContext, no_docs: bool) -> Result<Vec<IdlTypeDefinit
|
|||
.collect::<Vec<IdlEnumVariant>>();
|
||||
Some(Ok(IdlTypeDefinition {
|
||||
name,
|
||||
path: None,
|
||||
generics: None,
|
||||
docs: doc,
|
||||
ty: IdlTypeDefinitionTy::Enum { variants },
|
||||
}))
|
||||
|
@ -547,7 +553,7 @@ fn idl_accounts(
|
|||
},
|
||||
is_optional: if acc.is_optional { Some(true) } else { None },
|
||||
docs: if !no_docs { acc.docs.clone() } else { None },
|
||||
pda: pda::parse(ctx, accounts, acc, seeds_feature),
|
||||
pda: super::pda::parse(ctx, accounts, acc, seeds_feature),
|
||||
relations: relations::parse(acc, seeds_feature),
|
||||
}),
|
||||
})
|
|
@ -0,0 +1,120 @@
|
|||
use crate::idl::types::*;
|
||||
|
||||
pub mod file;
|
||||
pub mod pda;
|
||||
pub mod relations;
|
||||
|
||||
impl std::str::FromStr for IdlType {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut s = s.to_string();
|
||||
fn array_from_str(inner: &str) -> IdlType {
|
||||
match inner.strip_suffix(']') {
|
||||
None => {
|
||||
let (raw_type, raw_length) = inner.rsplit_once(';').unwrap();
|
||||
let ty = IdlType::from_str(raw_type).unwrap();
|
||||
let len = raw_length.replace('_', "").parse::<usize>().unwrap();
|
||||
IdlType::Array(Box::new(ty), len)
|
||||
}
|
||||
Some(nested_inner) => array_from_str(&nested_inner[1..]),
|
||||
}
|
||||
}
|
||||
s.retain(|c| !c.is_whitespace());
|
||||
|
||||
let r = match s.as_str() {
|
||||
"bool" => IdlType::Bool,
|
||||
"u8" => IdlType::U8,
|
||||
"i8" => IdlType::I8,
|
||||
"u16" => IdlType::U16,
|
||||
"i16" => IdlType::I16,
|
||||
"u32" => IdlType::U32,
|
||||
"i32" => IdlType::I32,
|
||||
"f32" => IdlType::F32,
|
||||
"u64" => IdlType::U64,
|
||||
"i64" => IdlType::I64,
|
||||
"f64" => IdlType::F64,
|
||||
"u128" => IdlType::U128,
|
||||
"i128" => IdlType::I128,
|
||||
"u256" => IdlType::U256,
|
||||
"i256" => IdlType::I256,
|
||||
"Vec<u8>" => IdlType::Bytes,
|
||||
"String" | "&str" | "&'staticstr" => IdlType::String,
|
||||
"Pubkey" => IdlType::PublicKey,
|
||||
_ => match s.to_string().strip_prefix("Option<") {
|
||||
None => match s.to_string().strip_prefix("Vec<") {
|
||||
None => {
|
||||
if s.to_string().starts_with('[') {
|
||||
array_from_str(&s)
|
||||
} else {
|
||||
IdlType::Defined(s.to_string())
|
||||
}
|
||||
}
|
||||
Some(inner) => {
|
||||
let inner_ty = Self::from_str(
|
||||
inner
|
||||
.strip_suffix('>')
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid option"))?,
|
||||
)?;
|
||||
IdlType::Vec(Box::new(inner_ty))
|
||||
}
|
||||
},
|
||||
Some(inner) => {
|
||||
let inner_ty = Self::from_str(
|
||||
inner
|
||||
.strip_suffix('>')
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid option"))?,
|
||||
)?;
|
||||
IdlType::Option(Box::new(inner_ty))
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::idl::types::IdlType;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn multidimensional_array() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("[[u8;16];32]").unwrap(),
|
||||
IdlType::Array(Box::new(IdlType::Array(Box::new(IdlType::U8), 16)), 32)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("[Pubkey;16]").unwrap(),
|
||||
IdlType::Array(Box::new(IdlType::PublicKey), 16)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_with_underscored_length() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("[u8;50_000]").unwrap(),
|
||||
IdlType::Array(Box::new(IdlType::U8), 50000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Option<bool>").unwrap(),
|
||||
IdlType::Option(Box::new(IdlType::Bool))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Vec<bool>").unwrap(),
|
||||
IdlType::Vec(Box::new(IdlType::Bool))
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::idl::*;
|
||||
use crate::idl::types::*;
|
||||
use crate::parser;
|
||||
use crate::parser::context::CrateContext;
|
||||
use crate::ConstraintSeedsGroup;
|
|
@ -0,0 +1,229 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Idl {
|
||||
pub version: String,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub constants: Vec<IdlConst>,
|
||||
pub instructions: Vec<IdlInstruction>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub accounts: Vec<IdlTypeDefinition>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub types: Vec<IdlTypeDefinition>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub events: Option<Vec<IdlEvent>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub errors: Option<Vec<IdlErrorCode>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub metadata: Option<JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlConst {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlState {
|
||||
#[serde(rename = "struct")]
|
||||
pub strct: IdlTypeDefinition,
|
||||
pub methods: Vec<IdlInstruction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlInstruction {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
pub accounts: Vec<IdlAccountItem>,
|
||||
pub args: Vec<IdlField>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub returns: Option<IdlType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlAccounts {
|
||||
pub name: String,
|
||||
pub accounts: Vec<IdlAccountItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum IdlAccountItem {
|
||||
IdlAccount(IdlAccount),
|
||||
IdlAccounts(IdlAccounts),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlAccount {
|
||||
pub name: String,
|
||||
pub is_mut: bool,
|
||||
pub is_signer: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_optional: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub pda: Option<IdlPda>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub relations: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlPda {
|
||||
pub seeds: Vec<IdlSeed>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub program_id: Option<IdlSeed>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase", tag = "kind")]
|
||||
pub enum IdlSeed {
|
||||
Const(IdlSeedConst),
|
||||
Arg(IdlSeedArg),
|
||||
Account(IdlSeedAccount),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlSeedAccount {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
// account_ty points to the entry in the "accounts" section.
|
||||
// Some only if the `Account<T>` type is used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub account: Option<String>,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlSeedArg {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IdlSeedConst {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub value: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlField {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEvent {
|
||||
pub name: String,
|
||||
pub fields: Vec<IdlEventField>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEventField {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlType,
|
||||
pub index: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlTypeDefinition {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub path: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub generics: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub docs: Option<Vec<String>>,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: IdlTypeDefinitionTy,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "lowercase", tag = "kind")]
|
||||
pub enum IdlTypeDefinitionTy {
|
||||
Struct { fields: Vec<IdlField> },
|
||||
Enum { variants: Vec<IdlEnumVariant> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEnumVariant {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub fields: Option<EnumFields>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum EnumFields {
|
||||
Named(Vec<IdlField>),
|
||||
Tuple(Vec<IdlType>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum IdlType {
|
||||
Bool,
|
||||
U8,
|
||||
I8,
|
||||
U16,
|
||||
I16,
|
||||
U32,
|
||||
I32,
|
||||
F32,
|
||||
U64,
|
||||
I64,
|
||||
F64,
|
||||
U128,
|
||||
I128,
|
||||
U256,
|
||||
I256,
|
||||
Bytes,
|
||||
String,
|
||||
PublicKey,
|
||||
Defined(String),
|
||||
Option(Box<IdlType>),
|
||||
Vec(Box<IdlType>),
|
||||
Array(Box<IdlType>, usize),
|
||||
GenericLenArray(Box<IdlType>, String),
|
||||
Generic(String),
|
||||
DefinedWithTypeArgs {
|
||||
path: String,
|
||||
args: Vec<IdlDefinedTypeArg>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum IdlDefinedTypeArg {
|
||||
Generic(String),
|
||||
Value(String),
|
||||
Type(IdlType),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct IdlErrorCode {
|
||||
pub code: u32,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||
pub msg: Option<String>,
|
||||
}
|
|
@ -23,7 +23,6 @@ pub mod codegen;
|
|||
pub mod hash;
|
||||
#[cfg(not(feature = "hash"))]
|
||||
pub(crate) mod hash;
|
||||
#[cfg(feature = "idl")]
|
||||
pub mod idl;
|
||||
pub mod parser;
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
[features]
|
||||
seeds = true
|
||||
|
||||
[programs.localnet]
|
||||
idl = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
idl_2 = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
|
@ -0,0 +1,13 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"programs/*"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
overflow-checks = true
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
[profile.release.build-override]
|
||||
opt-level = 3
|
||||
incremental = false
|
||||
codegen-units = 1
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
cd programs/idl
|
||||
anchor idl parse --file src/lib.rs > ../../tests/testdata/idl_parse_exp.json
|
||||
anchor idl build > ../../tests/testdata/idl_build_exp.json
|
||||
|
||||
cd ../generics
|
||||
anchor idl build > ../../tests/testdata/generics_build_exp.json
|
||||
|
||||
cd ../relations-derivation
|
||||
anchor idl build > ../../tests/testdata/relations_build_exp.json
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "idl-build",
|
||||
"version": "0.28.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": ">=17"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "generics"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "generics"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
cpi = ["no-entrypoint"]
|
||||
idl-build = [
|
||||
"anchor-lang/idl-build",
|
||||
"some-external-program/idl-build",
|
||||
]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
||||
anchor-spl = { path = "../../../../spl" }
|
||||
some-external-program = { path = "../some_external_program", features = ["no-entrypoint"] }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,80 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use some_external_program;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
/// This is an example program used for testing
|
||||
#[program]
|
||||
pub mod example_program {
|
||||
use super::*;
|
||||
|
||||
pub fn generic(
|
||||
ctx: Context<GenericCtx>,
|
||||
generic_field: GenericType::<u32, u64, 10>
|
||||
) -> Result<()>{
|
||||
ctx.accounts.generic_acc.data = generic_field;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct GenericCtx<'info> {
|
||||
generic_acc: Account<'info, GenericAccount>,
|
||||
|
||||
#[account(mut)]
|
||||
payer: Signer<'info>,
|
||||
system_program: Program<'info, System>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct GenericAccount {
|
||||
pub data: GenericType<u32, u64, 10>
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct GenericType<T, U, const N: usize>
|
||||
where
|
||||
T: AnchorSerialize + AnchorDeserialize,
|
||||
U: AnchorSerialize + AnchorDeserialize,
|
||||
{
|
||||
pub gen1: T,
|
||||
pub gen2: U,
|
||||
pub gen3: GenericNested<u32, U>,
|
||||
pub gen4: GenericNested<T, some_external_program::Baz>,
|
||||
pub gen5: GenericNested<T, U>,
|
||||
pub gen6: GenericNested<u32, u64>,
|
||||
pub gen7: GenericNested<T, GenericNested<T, U>>,
|
||||
pub arr: [u8; N],
|
||||
pub warr: WrappedU8Array<N>,
|
||||
pub warrval: WrappedU8Array<10>,
|
||||
pub enm1: GenericEnum<T, U, N>,
|
||||
pub enm2: GenericEnum<GenericNested<T, u64>, u32, 30>,
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Default)]
|
||||
pub struct GenericNested<V, Z>
|
||||
where
|
||||
V: AnchorSerialize + AnchorDeserialize,
|
||||
Z: AnchorSerialize + AnchorDeserialize,
|
||||
{
|
||||
pub gen1: V,
|
||||
pub gen2: Z,
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct WrappedU8Array<const N: usize>(u8);
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub enum GenericEnum<T, U, const N: usize>
|
||||
where
|
||||
T: AnchorSerialize + AnchorDeserialize,
|
||||
U: AnchorSerialize + AnchorDeserialize,
|
||||
{
|
||||
Unnamed(T, U),
|
||||
Named {
|
||||
gen1: T,
|
||||
gen2: U,
|
||||
},
|
||||
Struct(GenericNested<T, U>),
|
||||
Arr([T; N]),
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "idl"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "idl"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
cpi = ["no-entrypoint"]
|
||||
idl-build = [
|
||||
"anchor-lang/idl-build",
|
||||
"some-external-program/idl-build",
|
||||
]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
||||
anchor-spl = { path = "../../../../spl" }
|
||||
bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]}
|
||||
some-external-program = { path = "../some_external_program", features = ["no-entrypoint"] }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,326 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use some_external_program;
|
||||
use std::str::FromStr;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[constant]
|
||||
pub const FOO_CONST: u128 = 1_000_000;
|
||||
#[constant]
|
||||
pub const BAR_CONST: u8 = 6;
|
||||
|
||||
/// This is an example program used for testing
|
||||
#[program]
|
||||
pub mod example_program {
|
||||
use super::*;
|
||||
|
||||
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
|
||||
ctx.accounts.state.set_inner(State::default());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initializes an account with specified values
|
||||
pub fn initialize_with_values(
|
||||
ctx: Context<Initialize>,
|
||||
bool_field: bool,
|
||||
u8_field: u8,
|
||||
i8_field: i8,
|
||||
u16_field: u16,
|
||||
i16_field: i16,
|
||||
u32_field: u32,
|
||||
i32_field: i32,
|
||||
f32_field: f32,
|
||||
u64_field: u64,
|
||||
i64_field: i64,
|
||||
f64_field: f64,
|
||||
u128_field: u128,
|
||||
i128_field: i128,
|
||||
bytes_field: Vec<u8>,
|
||||
string_field: String,
|
||||
pubkey_field: Pubkey,
|
||||
vec_field: Vec<u64>,
|
||||
vec_struct_field: Vec<FooStruct>,
|
||||
option_field: Option<bool>,
|
||||
option_struct_field: Option<FooStruct>,
|
||||
struct_field: FooStruct,
|
||||
array_field: [bool; 3],
|
||||
enum_field_1: FooEnum,
|
||||
enum_field_2: FooEnum,
|
||||
enum_field_3: FooEnum,
|
||||
enum_field_4: FooEnum,
|
||||
) -> Result<()> {
|
||||
ctx.accounts.state.set_inner(State {
|
||||
bool_field,
|
||||
u8_field,
|
||||
i8_field,
|
||||
u16_field,
|
||||
i16_field,
|
||||
u32_field,
|
||||
i32_field,
|
||||
f32_field,
|
||||
u64_field,
|
||||
i64_field,
|
||||
f64_field,
|
||||
u128_field,
|
||||
i128_field,
|
||||
bytes_field,
|
||||
string_field,
|
||||
pubkey_field,
|
||||
vec_field,
|
||||
vec_struct_field,
|
||||
option_field,
|
||||
option_struct_field,
|
||||
struct_field,
|
||||
array_field,
|
||||
enum_field_1,
|
||||
enum_field_2,
|
||||
enum_field_3,
|
||||
enum_field_4,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// a separate instruction due to initialize_with_values having too many arguments
|
||||
/// https://github.com/solana-labs/solana/issues/23978
|
||||
pub fn initialize_with_values2(
|
||||
ctx: Context<Initialize2>,
|
||||
vec_of_option: Vec<Option<u64>>,
|
||||
box_field: Box<bool>,
|
||||
) -> Result<SomeRetStruct> {
|
||||
ctx.accounts.state.set_inner(State2 { vec_of_option, box_field });
|
||||
Ok(SomeRetStruct { some_field: 3})
|
||||
}
|
||||
|
||||
pub fn cause_error(_ctx: Context<CauseError>) -> Result<()> {
|
||||
return Err(error!(ErrorCode::SomeError));
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum type
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub enum FooEnum {
|
||||
/// Tuple kind
|
||||
Unnamed(bool, u8, BarStruct),
|
||||
UnnamedSingle(BarStruct),
|
||||
Named {
|
||||
/// A bool field inside a struct tuple kind
|
||||
bool_field: bool,
|
||||
u8_field: u8,
|
||||
nested: BarStruct,
|
||||
},
|
||||
Struct(BarStruct),
|
||||
OptionStruct(Option<BarStruct>),
|
||||
VecStruct(Vec<BarStruct>),
|
||||
NoFields,
|
||||
}
|
||||
|
||||
/// Bar struct type
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct BarStruct {
|
||||
/// Some field
|
||||
some_field: bool,
|
||||
other_field: u8,
|
||||
}
|
||||
|
||||
impl Default for BarStruct {
|
||||
fn default() -> Self {
|
||||
return BarStruct {
|
||||
some_field: true,
|
||||
other_field: 10,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct FooStruct {
|
||||
field1: u8,
|
||||
field2: u16,
|
||||
nested: BarStruct,
|
||||
vec_nested: Vec<BarStruct>,
|
||||
option_nested: Option<BarStruct>,
|
||||
enum_field: FooEnum,
|
||||
}
|
||||
|
||||
impl Default for FooStruct {
|
||||
fn default() -> Self {
|
||||
return FooStruct {
|
||||
field1: 123,
|
||||
field2: 999,
|
||||
nested: BarStruct::default(),
|
||||
vec_nested: vec![BarStruct::default()],
|
||||
option_nested: Some(BarStruct::default()),
|
||||
enum_field: FooEnum::Named {
|
||||
bool_field: true,
|
||||
u8_field: 15,
|
||||
nested: BarStruct::default(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// An account containing various fields
|
||||
#[account]
|
||||
pub struct State {
|
||||
/// A boolean field
|
||||
bool_field: bool,
|
||||
u8_field: u8,
|
||||
i8_field: i8,
|
||||
u16_field: u16,
|
||||
i16_field: i16,
|
||||
u32_field: u32,
|
||||
i32_field: i32,
|
||||
f32_field: f32,
|
||||
u64_field: u64,
|
||||
i64_field: i64,
|
||||
f64_field: f64,
|
||||
u128_field: u128,
|
||||
i128_field: i128,
|
||||
bytes_field: Vec<u8>,
|
||||
string_field: String,
|
||||
pubkey_field: Pubkey,
|
||||
vec_field: Vec<u64>,
|
||||
vec_struct_field: Vec<FooStruct>,
|
||||
option_field: Option<bool>,
|
||||
option_struct_field: Option<FooStruct>,
|
||||
struct_field: FooStruct,
|
||||
array_field: [bool; 3],
|
||||
enum_field_1: FooEnum,
|
||||
enum_field_2: FooEnum,
|
||||
enum_field_3: FooEnum,
|
||||
enum_field_4: FooEnum,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
// some arbitrary default values
|
||||
return State {
|
||||
bool_field: true,
|
||||
u8_field: 234,
|
||||
i8_field: -123,
|
||||
u16_field: 62345,
|
||||
i16_field: -31234,
|
||||
u32_field: 1234567891,
|
||||
i32_field: -1234567891,
|
||||
f32_field: 123456.5,
|
||||
u64_field: u64::MAX / 2 + 10,
|
||||
i64_field: i64::MIN / 2 - 10,
|
||||
f64_field: 1234567891.345,
|
||||
u128_field: u128::MAX / 2 + 10,
|
||||
i128_field: i128::MIN / 2 - 10,
|
||||
bytes_field: vec![1, 2, 255, 254],
|
||||
string_field: String::from("hello"),
|
||||
pubkey_field: Pubkey::from_str("EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7").unwrap(),
|
||||
vec_field: vec![1, 2, 100, 1000, u64::MAX],
|
||||
vec_struct_field: vec![FooStruct::default()],
|
||||
option_field: None,
|
||||
option_struct_field: Some(FooStruct::default()),
|
||||
struct_field: FooStruct::default(),
|
||||
array_field: [true, false, true],
|
||||
enum_field_1: FooEnum::Unnamed(false, 10, BarStruct::default()),
|
||||
enum_field_2: FooEnum::Named {
|
||||
bool_field: true,
|
||||
u8_field: 20,
|
||||
nested: BarStruct::default(),
|
||||
},
|
||||
enum_field_3: FooEnum::Struct(BarStruct::default()),
|
||||
enum_field_4: FooEnum::NoFields,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct State2 {
|
||||
vec_of_option: Vec<Option<u64>>,
|
||||
box_field: Box<bool>,
|
||||
}
|
||||
impl Default for State2 {
|
||||
fn default() -> Self {
|
||||
return State2 {
|
||||
vec_of_option: vec![None, Some(10)],
|
||||
box_field: Box::new(true),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct NestedAccounts<'info> {
|
||||
/// Sysvar clock
|
||||
clock: Sysvar<'info, Clock>,
|
||||
rent: Sysvar<'info, Rent>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
/// State account
|
||||
#[account(
|
||||
init,
|
||||
space = 8 + 1000, // TODO: use exact space required
|
||||
payer = payer,
|
||||
)]
|
||||
state: Account<'info, State>,
|
||||
|
||||
nested: NestedAccounts<'info>,
|
||||
zc_account: AccountLoader<'info, SomeZcAccount>,
|
||||
|
||||
#[account(mut)]
|
||||
payer: Signer<'info>,
|
||||
system_program: Program<'info, System>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize2<'info> {
|
||||
#[account(
|
||||
init,
|
||||
space = 8 + 1000, // TODO: use exact space required
|
||||
payer = payer,
|
||||
)]
|
||||
state: Account<'info, State2>,
|
||||
|
||||
#[account(mut)]
|
||||
payer: Signer<'info>,
|
||||
system_program: Program<'info, System>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct CauseError {}
|
||||
|
||||
#[error_code]
|
||||
pub enum ErrorCode {
|
||||
#[msg("Example error.")]
|
||||
SomeError,
|
||||
#[msg("Another error.")]
|
||||
OtherError,
|
||||
ErrorWithoutMsg,
|
||||
}
|
||||
|
||||
mod some_other_module {
|
||||
use super::*;
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct Baz {
|
||||
some_u8: u8,
|
||||
}
|
||||
}
|
||||
|
||||
#[event]
|
||||
pub struct SomeEvent {
|
||||
bool_field: bool,
|
||||
external_baz: some_external_program::Baz,
|
||||
other_module_baz: some_other_module::Baz,
|
||||
}
|
||||
|
||||
#[zero_copy]
|
||||
pub struct ZcStruct {
|
||||
pub some_field: u16,
|
||||
}
|
||||
|
||||
#[account(zero_copy)]
|
||||
pub struct SomeZcAccount {
|
||||
field: ZcStruct,
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct SomeRetStruct {
|
||||
pub some_field: u8,
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "relations-derivation"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
rust-version = "1.60"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "relations_derivation"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
cpi = ["no-entrypoint"]
|
||||
idl-build = [
|
||||
"anchor-lang/idl-build",
|
||||
]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,68 @@
|
|||
//! The typescript example serves to show how one would setup an Anchor
|
||||
//! workspace with TypeScript tests and migrations.
|
||||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod relations_derivation {
|
||||
use super::*;
|
||||
|
||||
pub fn init_base(ctx: Context<InitBase>) -> Result<()> {
|
||||
ctx.accounts.account.my_account = ctx.accounts.my_account.key();
|
||||
ctx.accounts.account.bump = ctx.bumps["account"];
|
||||
Ok(())
|
||||
}
|
||||
pub fn test_relation(_ctx: Context<TestRelation>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitBase<'info> {
|
||||
/// CHECK: yeah I know
|
||||
#[account(mut)]
|
||||
my_account: Signer<'info>,
|
||||
#[account(
|
||||
init,
|
||||
payer = my_account,
|
||||
seeds = [b"seed"],
|
||||
space = 100,
|
||||
bump,
|
||||
)]
|
||||
account: Account<'info, MyAccount>,
|
||||
system_program: Program<'info, System>
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Nested<'info> {
|
||||
/// CHECK: yeah I know
|
||||
my_account: UncheckedAccount<'info>,
|
||||
#[account(
|
||||
has_one = my_account,
|
||||
seeds = [b"seed"],
|
||||
bump = account.bump
|
||||
)]
|
||||
account: Account<'info, MyAccount>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestRelation<'info> {
|
||||
/// CHECK: yeah I know
|
||||
my_account: UncheckedAccount<'info>,
|
||||
#[account(
|
||||
has_one = my_account,
|
||||
seeds = [b"seed"],
|
||||
bump = account.bump
|
||||
)]
|
||||
account: Account<'info, MyAccount>,
|
||||
nested: Nested<'info>,
|
||||
}
|
||||
|
||||
|
||||
#[account]
|
||||
pub struct MyAccount {
|
||||
pub my_account: Pubkey,
|
||||
pub bump: u8
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "some-external-program"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "some_external_program"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
idl-build = ["anchor-lang/idl-build"]
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
||||
anchor-spl = { path = "../../../../spl" }
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,20 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod idl_2 {
|
||||
use super::*;
|
||||
|
||||
pub fn initialize(_ctx: Context<Initialize>, _baz: Baz) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct Baz {
|
||||
some_field: u8,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize {}
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
|
||||
cd programs/idl
|
||||
anchor idl parse --file src/lib.rs > $TMPDIR/idl_parse_act.json
|
||||
anchor idl build > $TMPDIR/idl_build_act.json
|
||||
|
||||
cd ../generics
|
||||
anchor idl build > $TMPDIR/generics_build_act.json
|
||||
|
||||
cd ../relations-derivation
|
||||
anchor idl build > $TMPDIR/relations_build_act.json
|
||||
|
||||
cd ../..
|
||||
echo "----------------------------------------------------"
|
||||
echo "idl parse before > after"
|
||||
echo "----------------------------------------------------"
|
||||
echo ""
|
||||
diff -y --color tests/testdata/idl_parse_exp.json $TMPDIR/idl_parse_act.json
|
||||
PARSE_RETCODE=$?
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "----------------------------------------------------"
|
||||
echo "idl build before > after"
|
||||
echo "----------------------------------------------------"
|
||||
echo ""
|
||||
diff -y --color tests/testdata/idl_build_exp.json $TMPDIR/idl_build_act.json
|
||||
GEN_RETCODE=$?
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "----------------------------------------------------"
|
||||
echo "idl generics build before > after"
|
||||
echo "----------------------------------------------------"
|
||||
echo ""
|
||||
diff -y --color tests/testdata/generics_build_exp.json $TMPDIR/generics_build_act.json
|
||||
GEN_GENERICS_RETCODE=$?
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "----------------------------------------------------"
|
||||
echo "idl relations build before > after"
|
||||
echo "----------------------------------------------------"
|
||||
echo ""
|
||||
diff -y --color tests/testdata/relations_build_exp.json $TMPDIR/relations_build_act.json
|
||||
GEN_RELATIONS_RETCODE=$?
|
||||
|
||||
# returns 0 when ok, or a positive integer when there are differences
|
||||
exit $((PARSE_RETCODE+GEN_RETCODE+GEN_GENERICS_RETCODE+GEN_RELATIONS_RETCODE))
|
|
@ -0,0 +1,426 @@
|
|||
{
|
||||
"version": "0.1.0",
|
||||
"name": "example_program",
|
||||
"docs": [
|
||||
"This is an example program used for testing"
|
||||
],
|
||||
"instructions": [
|
||||
{
|
||||
"name": "generic",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "genericAcc",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "genericField",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericType",
|
||||
"args": [
|
||||
{
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"value": "10"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "GenericAccount",
|
||||
"path": "generics::GenericAccount",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "data",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericType",
|
||||
"args": [
|
||||
{
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"value": "10"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": "GenericEnum",
|
||||
"path": "generics::GenericEnum",
|
||||
"generics": [
|
||||
"T",
|
||||
"U",
|
||||
"N"
|
||||
],
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "Unnamed",
|
||||
"fields": [
|
||||
{
|
||||
"generic": "T"
|
||||
},
|
||||
{
|
||||
"generic": "U"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Named",
|
||||
"fields": [
|
||||
{
|
||||
"name": "gen1",
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen2",
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Struct",
|
||||
"fields": [
|
||||
{
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Arr",
|
||||
"fields": [
|
||||
{
|
||||
"genericLenArray": [
|
||||
{
|
||||
"generic": "T"
|
||||
},
|
||||
"N"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GenericNested",
|
||||
"path": "generics::GenericNested",
|
||||
"generics": [
|
||||
"V",
|
||||
"Z"
|
||||
],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "gen1",
|
||||
"type": {
|
||||
"generic": "V"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen2",
|
||||
"type": {
|
||||
"generic": "Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GenericType",
|
||||
"path": "generics::GenericType",
|
||||
"generics": [
|
||||
"T",
|
||||
"U",
|
||||
"N"
|
||||
],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "gen1",
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen2",
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen3",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen4",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"defined": "some_external_program::Baz"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen5",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen6",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gen7",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arr",
|
||||
"type": {
|
||||
"genericLenArray": [
|
||||
"u8",
|
||||
"N"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "warr",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::WrappedU8Array",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "N"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "warrval",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::WrappedU8Array",
|
||||
"args": [
|
||||
{
|
||||
"value": "10"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enm1",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericEnum",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"generic": "U"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"generic": "N"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enm2",
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericEnum",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"definedWithTypeArgs": {
|
||||
"path": "generics::GenericNested",
|
||||
"args": [
|
||||
{
|
||||
"type": {
|
||||
"generic": "T"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"value": "30"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Baz",
|
||||
"path": "some_external_program::Baz",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,727 @@
|
|||
{
|
||||
"version": "0.1.0",
|
||||
"name": "example_program",
|
||||
"docs": [
|
||||
"This is an example program used for testing"
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"name": "BAR_CONST",
|
||||
"type": "u8",
|
||||
"value": "6"
|
||||
},
|
||||
{
|
||||
"name": "FOO_CONST",
|
||||
"type": "u128",
|
||||
"value": "1000000"
|
||||
}
|
||||
],
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initialize",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "state",
|
||||
"isMut": true,
|
||||
"isSigner": true,
|
||||
"docs": [
|
||||
"State account"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "clock",
|
||||
"isMut": false,
|
||||
"isSigner": false,
|
||||
"docs": [
|
||||
"Sysvar clock"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zcAccount",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "initializeWithValues",
|
||||
"docs": [
|
||||
"Initializes an account with specified values"
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "state",
|
||||
"isMut": true,
|
||||
"isSigner": true,
|
||||
"docs": [
|
||||
"State account"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "clock",
|
||||
"isMut": false,
|
||||
"isSigner": false,
|
||||
"docs": [
|
||||
"Sysvar clock"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zcAccount",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "u8Field",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "i8Field",
|
||||
"type": "i8"
|
||||
},
|
||||
{
|
||||
"name": "u16Field",
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"name": "i16Field",
|
||||
"type": "i16"
|
||||
},
|
||||
{
|
||||
"name": "u32Field",
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "i32Field",
|
||||
"type": "i32"
|
||||
},
|
||||
{
|
||||
"name": "f32Field",
|
||||
"type": "f32"
|
||||
},
|
||||
{
|
||||
"name": "u64Field",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "i64Field",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "f64Field",
|
||||
"type": "f64"
|
||||
},
|
||||
{
|
||||
"name": "u128Field",
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "i128Field",
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "bytesField",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "stringField",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "pubkeyField",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "vecField",
|
||||
"type": {
|
||||
"vec": "u64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vecStructField",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "idl::FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionField",
|
||||
"type": {
|
||||
"option": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionStructField",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "idl::FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "structField",
|
||||
"type": {
|
||||
"defined": "idl::FooStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arrayField",
|
||||
"type": {
|
||||
"array": [
|
||||
"bool",
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField1",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField2",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField3",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField4",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "initializeWithValues2",
|
||||
"docs": [
|
||||
"a separate instruction due to initialize_with_values having too many arguments",
|
||||
"https://github.com/solana-labs/solana/issues/23978"
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "state",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "vecOfOption",
|
||||
"type": {
|
||||
"vec": {
|
||||
"option": "u64"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "boxField",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"defined": "idl::SomeRetStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "causeError",
|
||||
"accounts": [],
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "SomeZcAccount",
|
||||
"path": "idl::SomeZcAccount",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "field",
|
||||
"type": {
|
||||
"defined": "idl::ZcStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "State",
|
||||
"path": "idl::State",
|
||||
"docs": [
|
||||
"An account containing various fields"
|
||||
],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"docs": [
|
||||
"A boolean field"
|
||||
],
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "u8Field",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "i8Field",
|
||||
"type": "i8"
|
||||
},
|
||||
{
|
||||
"name": "u16Field",
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"name": "i16Field",
|
||||
"type": "i16"
|
||||
},
|
||||
{
|
||||
"name": "u32Field",
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "i32Field",
|
||||
"type": "i32"
|
||||
},
|
||||
{
|
||||
"name": "f32Field",
|
||||
"type": "f32"
|
||||
},
|
||||
{
|
||||
"name": "u64Field",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "i64Field",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "f64Field",
|
||||
"type": "f64"
|
||||
},
|
||||
{
|
||||
"name": "u128Field",
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "i128Field",
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "bytesField",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "stringField",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "pubkeyField",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "vecField",
|
||||
"type": {
|
||||
"vec": "u64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vecStructField",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "idl::FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionField",
|
||||
"type": {
|
||||
"option": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionStructField",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "idl::FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "structField",
|
||||
"type": {
|
||||
"defined": "idl::FooStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arrayField",
|
||||
"type": {
|
||||
"array": [
|
||||
"bool",
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField1",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField2",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField3",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField4",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "State2",
|
||||
"path": "idl::State2",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "vecOfOption",
|
||||
"type": {
|
||||
"vec": {
|
||||
"option": "u64"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "boxField",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": "BarStruct",
|
||||
"path": "idl::BarStruct",
|
||||
"docs": [
|
||||
"Bar struct type"
|
||||
],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"docs": [
|
||||
"Some field"
|
||||
],
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "otherField",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FooEnum",
|
||||
"path": "idl::FooEnum",
|
||||
"docs": [
|
||||
"Enum type"
|
||||
],
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "Unnamed",
|
||||
"fields": [
|
||||
"bool",
|
||||
"u8",
|
||||
{
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UnnamedSingle",
|
||||
"fields": [
|
||||
{
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Named",
|
||||
"fields": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"docs": [
|
||||
"A bool field inside a struct tuple kind"
|
||||
],
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "u8Field",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"type": {
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Struct",
|
||||
"fields": [
|
||||
{
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OptionStruct",
|
||||
"fields": [
|
||||
{
|
||||
"option": {
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "VecStruct",
|
||||
"fields": [
|
||||
{
|
||||
"vec": {
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NoFields"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FooStruct",
|
||||
"path": "idl::FooStruct",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "field1",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "field2",
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"type": {
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vecNested",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionNested",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "idl::BarStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField",
|
||||
"type": {
|
||||
"defined": "idl::FooEnum"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SomeRetStruct",
|
||||
"path": "idl::SomeRetStruct",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ZcStruct",
|
||||
"path": "idl::ZcStruct",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"type": "u16"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Baz",
|
||||
"path": "idl::some_other_module::Baz",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someU8",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Baz",
|
||||
"path": "some_external_program::Baz",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "SomeEvent",
|
||||
"fields": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"type": "bool",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "externalBaz",
|
||||
"type": {
|
||||
"defined": "some_external_program::Baz"
|
||||
},
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "otherModuleBaz",
|
||||
"type": {
|
||||
"defined": "idl::some_other_module::Baz"
|
||||
},
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"errors": [
|
||||
{
|
||||
"code": 6000,
|
||||
"name": "SomeError",
|
||||
"msg": "Example error."
|
||||
},
|
||||
{
|
||||
"code": 6001,
|
||||
"name": "OtherError",
|
||||
"msg": "Another error."
|
||||
},
|
||||
{
|
||||
"code": 6002,
|
||||
"name": "ErrorWithoutMsg"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,705 @@
|
|||
{
|
||||
"version": "0.1.0",
|
||||
"name": "example_program",
|
||||
"docs": [
|
||||
"This is an example program used for testing"
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"name": "FOO_CONST",
|
||||
"type": "u128",
|
||||
"value": "1_000_000"
|
||||
},
|
||||
{
|
||||
"name": "BAR_CONST",
|
||||
"type": "u8",
|
||||
"value": "6"
|
||||
}
|
||||
],
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initialize",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "state",
|
||||
"isMut": true,
|
||||
"isSigner": true,
|
||||
"docs": [
|
||||
"State account"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "clock",
|
||||
"isMut": false,
|
||||
"isSigner": false,
|
||||
"docs": [
|
||||
"Sysvar clock"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zcAccount",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "initializeWithValues",
|
||||
"docs": [
|
||||
"Initializes an account with specified values"
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "state",
|
||||
"isMut": true,
|
||||
"isSigner": true,
|
||||
"docs": [
|
||||
"State account"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "clock",
|
||||
"isMut": false,
|
||||
"isSigner": false,
|
||||
"docs": [
|
||||
"Sysvar clock"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zcAccount",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "u8Field",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "i8Field",
|
||||
"type": "i8"
|
||||
},
|
||||
{
|
||||
"name": "u16Field",
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"name": "i16Field",
|
||||
"type": "i16"
|
||||
},
|
||||
{
|
||||
"name": "u32Field",
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "i32Field",
|
||||
"type": "i32"
|
||||
},
|
||||
{
|
||||
"name": "f32Field",
|
||||
"type": "f32"
|
||||
},
|
||||
{
|
||||
"name": "u64Field",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "i64Field",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "f64Field",
|
||||
"type": "f64"
|
||||
},
|
||||
{
|
||||
"name": "u128Field",
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "i128Field",
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "bytesField",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "stringField",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "pubkeyField",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "vecField",
|
||||
"type": {
|
||||
"vec": "u64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vecStructField",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionField",
|
||||
"type": {
|
||||
"option": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionStructField",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "structField",
|
||||
"type": {
|
||||
"defined": "FooStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arrayField",
|
||||
"type": {
|
||||
"array": [
|
||||
"bool",
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField1",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField2",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField3",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField4",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "initializeWithValues2",
|
||||
"docs": [
|
||||
"a separate instruction due to initialize_with_values having too many arguments",
|
||||
"https://github.com/solana-labs/solana/issues/23978"
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "state",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "vecOfOption",
|
||||
"type": {
|
||||
"vec": {
|
||||
"option": "u64"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "boxField",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"defined": "SomeRetStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "causeError",
|
||||
"accounts": [],
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "State",
|
||||
"docs": [
|
||||
"An account containing various fields"
|
||||
],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"docs": [
|
||||
"A boolean field"
|
||||
],
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "u8Field",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "i8Field",
|
||||
"type": "i8"
|
||||
},
|
||||
{
|
||||
"name": "u16Field",
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"name": "i16Field",
|
||||
"type": "i16"
|
||||
},
|
||||
{
|
||||
"name": "u32Field",
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "i32Field",
|
||||
"type": "i32"
|
||||
},
|
||||
{
|
||||
"name": "f32Field",
|
||||
"type": "f32"
|
||||
},
|
||||
{
|
||||
"name": "u64Field",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "i64Field",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "f64Field",
|
||||
"type": "f64"
|
||||
},
|
||||
{
|
||||
"name": "u128Field",
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "i128Field",
|
||||
"type": "i128"
|
||||
},
|
||||
{
|
||||
"name": "bytesField",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "stringField",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "pubkeyField",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "vecField",
|
||||
"type": {
|
||||
"vec": "u64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vecStructField",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionField",
|
||||
"type": {
|
||||
"option": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionStructField",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "FooStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "structField",
|
||||
"type": {
|
||||
"defined": "FooStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arrayField",
|
||||
"type": {
|
||||
"array": [
|
||||
"bool",
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField1",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField2",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField3",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField4",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "State2",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "vecOfOption",
|
||||
"type": {
|
||||
"vec": {
|
||||
"option": "u64"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "boxField",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SomeZcAccount",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "field",
|
||||
"type": {
|
||||
"defined": "ZcStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": "Baz",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someU8",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BarStruct",
|
||||
"docs": [
|
||||
"Bar struct type"
|
||||
],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"docs": [
|
||||
"Some field"
|
||||
],
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "otherField",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FooStruct",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "field1",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "field2",
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"type": {
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vecNested",
|
||||
"type": {
|
||||
"vec": {
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "optionNested",
|
||||
"type": {
|
||||
"option": {
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enumField",
|
||||
"type": {
|
||||
"defined": "FooEnum"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ZcStruct",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"type": "u16"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SomeRetStruct",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "someField",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FooEnum",
|
||||
"docs": [
|
||||
"Enum type"
|
||||
],
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "Unnamed",
|
||||
"fields": [
|
||||
"bool",
|
||||
"u8",
|
||||
{
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UnnamedSingle",
|
||||
"fields": [
|
||||
{
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Named",
|
||||
"fields": [
|
||||
{
|
||||
"name": "bool_field",
|
||||
"docs": [
|
||||
"A bool field inside a struct tuple kind"
|
||||
],
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "u8_field",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"type": {
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Struct",
|
||||
"fields": [
|
||||
{
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OptionStruct",
|
||||
"fields": [
|
||||
{
|
||||
"option": {
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "VecStruct",
|
||||
"fields": [
|
||||
{
|
||||
"vec": {
|
||||
"defined": "BarStruct"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NoFields"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "SomeEvent",
|
||||
"fields": [
|
||||
{
|
||||
"name": "boolField",
|
||||
"type": "bool",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "externalBaz",
|
||||
"type": {
|
||||
"defined": "some_external_program::Baz"
|
||||
},
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "otherModuleBaz",
|
||||
"type": {
|
||||
"defined": "some_other_module::Baz"
|
||||
},
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"errors": [
|
||||
{
|
||||
"code": 6000,
|
||||
"name": "SomeError",
|
||||
"msg": "Example error."
|
||||
},
|
||||
{
|
||||
"code": 6001,
|
||||
"name": "OtherError",
|
||||
"msg": "Another error."
|
||||
},
|
||||
{
|
||||
"code": 6002,
|
||||
"name": "ErrorWithoutMsg"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"version": "0.1.0",
|
||||
"name": "relations_derivation",
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initBase",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "myAccount",
|
||||
"isMut": true,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "systemProgram",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "testRelation",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "myAccount",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": false,
|
||||
"isSigner": false,
|
||||
"relations": [
|
||||
"my_account"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nested",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "myAccount",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": false,
|
||||
"isSigner": false,
|
||||
"relations": [
|
||||
"my_account"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "MyAccount",
|
||||
"path": "relations_derivation::MyAccount",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "myAccount",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "bump",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
"escrow",
|
||||
"events",
|
||||
"floats",
|
||||
"idl-build",
|
||||
"ido-pool",
|
||||
"interface",
|
||||
"lockup",
|
||||
|
|
Loading…
Reference in New Issue