Prechádzať zdrojové kódy

idl: Fix missing `program::seed` resolution (#3474)

acheron 9 mesiacov pred
rodič
commit
fe4073301e

+ 1 - 0
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
 

+ 13 - 9
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::<Result<Vec<_>>>().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;

+ 19 - 0
tests/pda-derivation/programs/pda-derivation/src/lib.rs

@@ -55,6 +55,10 @@ pub mod pda_derivation {
     pub fn resolution_error(_ctx: Context<ResolutionError>) -> Result<()> {
         Ok(())
     }
+
+    pub fn unsupported_program_seed(_ctx: Context<UnsupportedProgramSeed>) -> 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,

+ 8 - 0
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;
+  });
 });