Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions lang-v2/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2496,6 +2496,8 @@ fn gen_declared_program(name: &Ident, idl: &serde_json::Value) -> syn::Result<To
pub struct #marker_name;

impl anchor_lang_v2::Id for #marker_name {
const IDL_ADDRESS: &'static str = #address_lit;

fn id() -> anchor_lang_v2::Address {
super::ID
}
Expand Down Expand Up @@ -5936,4 +5938,57 @@ mod tests {
"interface mode must not emit entrypoint runtime: {generated}"
);
}

#[test]
fn nested_accounts_register_idl_deps_through_nested_wrapper() {
let input: syn::DeriveInput = syn::parse_quote! {
pub struct Outer {
pub nested: anchor_lang_v2::Nested<Inner>,
}
};

let generated = impl_accounts(&input).to_string();

assert!(
generated.contains(
"< anchor_lang_v2 :: Nested < Inner > as anchor_lang_v2 :: IdlAccountType > \
:: __register_idl_deps"
),
"nested accounts should forward IDL dep registration through the Nested wrapper: \
{generated}"
);
}

#[test]
fn declare_program_markers_emit_known_idl_addresses() {
let idl = serde_json::json!({
"address": "Externa1111111111111111111111111111111111111",
"metadata": {
"name": "fixture",
"version": "0.1.0",
"spec": "0.1.0"
},
"instructions": [{
"name": "ping",
"discriminator": [1, 2, 3, 4, 5, 6, 7, 8],
"accounts": [],
"args": []
}],
"accounts": [],
"types": []
});
let name: syn::Ident = syn::parse_quote!(fixture);

let generated = gen_declared_program(&name, &idl)
.expect("fixture IDL should generate")
.to_string();

assert!(
generated.contains(
"const IDL_ADDRESS : & 'static str = \"Externa1111111111111111111111111111111111111\""
),
"declare_program markers should expose their known address for IDL emission: \
{generated}"
);
}
}
2 changes: 1 addition & 1 deletion lang-v2/derive/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ pub fn parse_field(
idl_address_v1_source: None,
idl_docs: vec![],
idl_pda: None,
idl_field_ty: None,
idl_field_ty: Some(field_ty.clone()),
});
}

Expand Down
39 changes: 39 additions & 0 deletions tests-v2/programs/accounts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1042,3 +1042,42 @@ pub struct CheckAssociatedTokenProgramSeed {
#[account(seeds = [b"vault"], bump, seeds::program = AssociatedToken::id())]
pub data: UncheckedAccount,
}

#[account]
pub struct NestedVault {
pub value: u64,
}

#[derive(Accounts)]
pub struct NestedIdlDepsInner {
pub vault: Account<NestedVault>,
}

#[cfg(feature = "idl-build")]
impl IdlAccountType for NestedIdlDepsInner {
fn __register_idl_deps(accounts: &mut Vec<&'static str>, types: &mut Vec<&'static str>) {
<Account<NestedVault> as IdlAccountType>::__register_idl_deps(accounts, types);
}
}

#[derive(Accounts)]
pub struct NestedIdlDepsOuter {
pub inner: Nested<NestedIdlDepsInner>,
}

#[derive(Accounts)]
pub struct NestedNoDepsInner {
pub authority: Signer,
}

#[cfg(feature = "idl-build")]
impl IdlAccountType for NestedNoDepsInner {
fn __register_idl_deps(accounts: &mut Vec<&'static str>, types: &mut Vec<&'static str>) {
<Signer as IdlAccountType>::__register_idl_deps(accounts, types);
}
}

#[derive(Accounts)]
pub struct NestedNoDepsOuter {
pub inner: Nested<NestedNoDepsInner>,
}
35 changes: 35 additions & 0 deletions tests-v2/tests/idl_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
anchor_lang_idl_spec::{IdlInstructionAccount, IdlInstructionAccountItem, IdlSeed},
anchor_lang_v2::{programs::AssociatedToken, Id},
declare_program_surface::surface,
};

fn parse_accounts(json: &str) -> Vec<IdlInstructionAccountItem> {
Expand Down Expand Up @@ -31,3 +32,37 @@ fn marker_id_program_seed_emits_marker_address_bytes() {
other => panic!("expected const program seed, got {other:?}"),
}
}

#[test]
fn nested_accounts_register_transitive_idl_deps() {
let mut accounts = Vec::new();
let mut types = Vec::new();
accounts_test::NestedIdlDepsOuter::__idl_register_deps(&mut accounts, &mut types);

assert!(
accounts.iter().any(|entry| entry.contains("\"name\":\"NestedVault\"")),
"nested account data should register its account entry: {accounts:?}"
);
assert!(
types.iter().any(|entry| entry.contains("\"name\":\"NestedVault\"")),
"nested account data should register its type entry: {types:?}"
);
}

#[test]
fn nested_accounts_without_data_do_not_invent_idl_deps() {
let mut accounts = Vec::new();
let mut types = Vec::new();
accounts_test::NestedNoDepsOuter::__idl_register_deps(&mut accounts, &mut types);

assert!(accounts.is_empty(), "expected no account deps, got {accounts:?}");
assert!(types.is_empty(), "expected no type deps, got {types:?}");
}

#[test]
fn declared_program_markers_expose_known_idl_address() {
assert_eq!(
surface::program::Surface::IDL_ADDRESS,
"D9t6cEFPTDWmTZfcikokLbnuuyeJT6oXnpEbyXB45LU2"
);
}
Loading