diff --git a/CHANGELOG.md b/CHANGELOG.md index 7891ff500d..e543f458ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ The minor version will be incremented upon a breaking change and the patch versi - lang: Make tuple struct fields public in `declare_program!` ([#2994](https://github.com/coral-xyz/anchor/pull/2994)). - Remove `rust-version` from crate manifests ([#3000](https://github.com/coral-xyz/anchor/pull/3000)). - cli: Fix upgradeable program clones ([#3010](https://github.com/coral-xyz/anchor/pull/3010)). +- ts: Fix using IDLs that have defined types as generic arguments ([#3016](https://github.com/coral-xyz/anchor/pull/3016)). ### Breaking diff --git a/tests/idl/programs/new-idl/src/lib.rs b/tests/idl/programs/new-idl/src/lib.rs index 7e706d25f3..65d05198b1 100644 --- a/tests/idl/programs/new-idl/src/lib.rs +++ b/tests/idl/programs/new-idl/src/lib.rs @@ -112,6 +112,14 @@ pub mod new_idl { Ok(()) } + pub fn generic_custom_struct( + ctx: Context, + generic_arg: GenericStruct, + ) -> Result<()> { + ctx.accounts.my_account.field = generic_arg; + Ok(()) + } + pub fn full_path( ctx: Context, named_struct: NamedStruct, @@ -315,11 +323,36 @@ pub struct Generic<'info> { pub system_program: Program<'info, System>, } +#[derive(Accounts)] +pub struct GenericCustomStruct<'info> { + #[account(mut)] + pub signer: Signer<'info>, + #[account( + init, + payer = signer, + space = 1024, + seeds = [b"genericCustomStruct", signer.key.as_ref()], + bump + )] + pub my_account: Account<'info, GenericAccountCustomStruct>, + pub system_program: Program<'info, System>, +} + #[account] pub struct GenericAccount { pub field: GenericStruct, } +#[account] +pub struct GenericAccountCustomStruct { + pub field: GenericStruct, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct SomeStruct { + pub field: u16, +} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] pub struct GenericStruct { arr: [T; N], diff --git a/tests/idl/tests/new-idl.ts b/tests/idl/tests/new-idl.ts index 443dcb3e6c..2b05515756 100644 --- a/tests/idl/tests/new-idl.ts +++ b/tests/idl/tests/new-idl.ts @@ -347,6 +347,28 @@ describe("New IDL", () => { assert.deepEqual(myAccount.field, arg); }); + it("Can use generics populated with custom struct", async () => { + const arg = { + arr: [{ field: 1 }, { field: 2 }, { field: 3 }, { field: 4 }], + subField: { + subArr: new Array(8).fill(null).map((_, i) => ({ field: i })), + another: [ + { field: 42 }, + { field: 420 }, + { field: 4_200 }, + { field: 42_000 }, + ], + }, + }; + const { pubkeys } = await program.methods + .genericCustomStruct(arg) + .rpcAndKeys(); + const myAccount = await program.account.genericAccountCustomStruct.fetch( + pubkeys.myAccount + ); + assert.deepEqual(myAccount.field, arg); + }); + it("Can use full module path types", async () => { const kp = anchor.web3.Keypair.generate(); diff --git a/ts/packages/anchor/src/coder/borsh/idl.ts b/ts/packages/anchor/src/coder/borsh/idl.ts index e682f2dcd5..0ef29cca4b 100644 --- a/ts/packages/anchor/src/coder/borsh/idl.ts +++ b/ts/packages/anchor/src/coder/borsh/idl.ts @@ -126,7 +126,10 @@ export class IdlCoder { throw new IdlError(`Invalid generic field: ${field.name}`); } - return IdlCoder.fieldLayout({ ...field, type: genericArg.type }); + return IdlCoder.fieldLayout( + { ...field, type: genericArg.type }, + types + ); } throw new IdlError(