diff --git a/CHANGELOG.md b/CHANGELOG.md index bf27615ca6..062d0d61e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ The minor version will be incremented upon a breaking change and the patch versi - ts: Fix loading programs with numbers in their names using `workspace` ([#3450](https://github.com/coral-xyz/anchor/pull/3450)). - lang: Remove a potential panic while getting the IDL in `declare_program!` ([#3458](https://github.com/coral-xyz/anchor/pull/3458)). - cli: Fix altering user-provided lib names ([#3467](https://github.com/coral-xyz/anchor/pull/3467)). +- idl: Fix missing `program::seed` resolution ([#3474](https://github.com/coral-xyz/anchor/pull/3474)). ### Breaking diff --git a/lang/syn/src/idl/accounts.rs b/lang/syn/src/idl/accounts.rs index 4d32b0a19a..3d0051ffbf 100644 --- a/lang/syn/src/idl/accounts.rs +++ b/lang/syn/src/idl/accounts.rs @@ -3,7 +3,7 @@ use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use super::common::{get_idl_module_path, get_no_docs}; -use crate::{AccountField, AccountsStruct, Field, InitKind, Ty}; +use crate::{AccountField, AccountsStruct, ConstraintSeedsGroup, Field, InitKind, Ty}; /// Generate the IDL build impl for the Accounts struct. pub fn gen_idl_build_impl_accounts_struct(accounts: &AccountsStruct) -> TokenStream { @@ -189,21 +189,25 @@ fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream { let pda = seed_constraints .map(|seed| seed.seeds.iter().map(parse_default)) .and_then(|seeds| seeds.collect::>>().ok()) - .map(|seeds| { - let program = seed_constraints - .and_then(|seed| seed.program_seed.as_ref()) - .and_then(|program| parse_default(program).ok()) - .map(|program| quote! { Some(#program) }) - .unwrap_or_else(|| quote! { None }); + .and_then(|seeds| { + let program = match seed_constraints { + Some(ConstraintSeedsGroup { + program_seed: Some(program), + .. + }) => parse_default(program) + .map(|program| quote! { Some(#program) }) + .ok()?, + _ => quote! { None }, + }; - quote! { + Some(quote! { Some( #idl::IdlPda { seeds: vec![#(#seeds),*], program: #program, } ) - } + }) }); if let Some(pda) = pda { return pda; diff --git a/tests/pda-derivation/programs/pda-derivation/src/lib.rs b/tests/pda-derivation/programs/pda-derivation/src/lib.rs index 603dc51cad..5b2a4bd6f5 100644 --- a/tests/pda-derivation/programs/pda-derivation/src/lib.rs +++ b/tests/pda-derivation/programs/pda-derivation/src/lib.rs @@ -55,6 +55,10 @@ pub mod pda_derivation { pub fn resolution_error(_ctx: Context) -> Result<()> { Ok(()) } + + pub fn unsupported_program_seed(_ctx: Context) -> Result<()> { + Ok(()) + } } #[derive(Accounts)] @@ -191,6 +195,21 @@ pub struct ResolutionError<'info> { pub another_pda: UncheckedAccount<'info>, } +#[derive(Accounts)] + +pub struct UnsupportedProgramSeed<'info> { + #[account( + seeds = [], + seeds::program = external_function_with_an_argument(&pda.key), + bump + )] + pub pda: UncheckedAccount<'info>, +} + +fn external_function_with_an_argument(pk: &Pubkey) -> Pubkey { + *pk +} + #[account] pub struct MyAccount { data: u64, diff --git a/tests/pda-derivation/tests/typescript.spec.ts b/tests/pda-derivation/tests/typescript.spec.ts index ec56ff9159..8c4059d3e7 100644 --- a/tests/pda-derivation/tests/typescript.spec.ts +++ b/tests/pda-derivation/tests/typescript.spec.ts @@ -134,4 +134,12 @@ describe("typescript", () => { ); } }); + + it("Skips resolution if `program::seeds` expression is not supported", async () => { + const acc = program.idl.instructions + .find((ix) => ix.name === "unsupportedProgramSeed")! + .accounts.find((acc) => acc.name === "pda")!; + // @ts-expect-error + expect(acc.pda).to.be.undefined; + }); });