浏览代码

lang: Add composite accounts support for `declare_program!` (#2894)

acheron 1 年之前
父节点
当前提交
01839ad725

+ 13 - 1
lang/attribute/program/src/declare_program/mods/internal.rs

@@ -145,7 +145,19 @@ fn gen_internal_accounts_common(
                         pub #name: #acc_expr
                     }
                 }
-                IdlInstructionAccountItem::Composite(_accs) => todo!("Composite"),
+                IdlInstructionAccountItem::Composite(accs) => {
+                    let name = format_ident!("{}", accs.name);
+                    let ty_name = idl
+                        .instructions
+                        .iter()
+                        .find(|ix| ix.accounts == accs.accounts)
+                        .map(|ix| format_ident!("{}", ix.name.to_camel_case()))
+                        .expect("Instruction must exist");
+
+                    quote! {
+                        pub #name: #ty_name #generics
+                    }
+                }
             });
 
             quote! {

+ 42 - 0
tests/declare-program/idls/external.json

@@ -80,6 +80,48 @@
           "type": "u32"
         }
       ]
+    },
+    {
+      "name": "update_composite",
+      "discriminator": [
+        26,
+        42,
+        201,
+        224,
+        121,
+        60,
+        188,
+        220
+      ],
+      "accounts": [
+        {
+          "name": "update",
+          "accounts": [
+            {
+              "name": "authority",
+              "signer": true
+            },
+            {
+              "name": "my_account",
+              "writable": true,
+              "pda": {
+                "seeds": [
+                  {
+                    "kind": "account",
+                    "path": "authority"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      ],
+      "args": [
+        {
+          "name": "value",
+          "type": "u32"
+        }
+      ]
     }
   ],
   "accounts": [

+ 20 - 0
tests/declare-program/programs/declare-program/src/lib.rs

@@ -28,6 +28,26 @@ pub mod declare_program {
 
         Ok(())
     }
+
+    pub fn cpi_composite(ctx: Context<Cpi>, value: u32) -> Result<()> {
+        let cpi_my_account = &mut ctx.accounts.cpi_my_account;
+
+        let cpi_ctx = CpiContext::new(
+            ctx.accounts.external_program.to_account_info(),
+            external::cpi::accounts::UpdateComposite {
+                update: external::cpi::accounts::Update {
+                    authority: ctx.accounts.authority.to_account_info(),
+                    my_account: cpi_my_account.to_account_info(),
+                },
+            },
+        );
+        external::cpi::update_composite(cpi_ctx, value)?;
+
+        cpi_my_account.reload()?;
+        require_eq!(cpi_my_account.field, value);
+
+        Ok(())
+    }
 }
 
 #[derive(Accounts)]

+ 10 - 0
tests/declare-program/programs/external/src/lib.rs

@@ -14,6 +14,11 @@ pub mod external {
         ctx.accounts.my_account.field = value;
         Ok(())
     }
+
+    pub fn update_composite(ctx: Context<UpdateComposite>, value: u32) -> Result<()> {
+        ctx.accounts.update.my_account.field = value;
+        Ok(())
+    }
 }
 
 #[derive(Accounts)]
@@ -38,6 +43,11 @@ pub struct Update<'info> {
     pub my_account: Account<'info, MyAccount>,
 }
 
+#[derive(Accounts)]
+pub struct UpdateComposite<'info> {
+    pub update: Update<'info>,
+}
+
 #[account]
 pub struct MyAccount {
     pub field: u32,

+ 24 - 2
tests/declare-program/tests/declare-program.ts

@@ -10,9 +10,18 @@ describe("declare-program", () => {
     anchor.workspace.declareProgram;
   const externalProgram: anchor.Program<External> = anchor.workspace.external;
 
-  it("Can CPI", async () => {
-    const { pubkeys } = await externalProgram.methods.init().rpcAndKeys();
+  // TODO: Add a utility type that does this?
+  let pubkeys: Awaited<
+    ReturnType<
+      ReturnType<typeof externalProgram["methods"]["init"]>["rpcAndKeys"]
+    >
+  >["pubkeys"];
+
+  before(async () => {
+    pubkeys = (await externalProgram.methods.init().rpcAndKeys()).pubkeys;
+  });
 
+  it("Can CPI", async () => {
     const value = 5;
     await program.methods
       .cpi(value)
@@ -24,4 +33,17 @@ describe("declare-program", () => {
     );
     assert.strictEqual(myAccount.field, value);
   });
+
+  it("Can CPI composite", async () => {
+    const value = 3;
+    await program.methods
+      .cpiComposite(value)
+      .accounts({ cpiMyAccount: pubkeys.myAccount })
+      .rpc();
+
+    const myAccount = await externalProgram.account.myAccount.fetch(
+      pubkeys.myAccount
+    );
+    assert.strictEqual(myAccount.field, value);
+  });
 });