瀏覽代碼

lang: Make stack frames slimmer on ATA creation (#3065)

Andrei Silviu Dragnea 1 年之前
父節點
當前提交
5727865b65

+ 1 - 0
CHANGELOG.md

@@ -21,6 +21,7 @@ The minor version will be incremented upon a breaking change and the patch versi
 - idl: Make safety comment checks fail silently when program path env is not set ([#3045](https://github.com/coral-xyz/anchor/pull/3045)).
 - idl: Avoid interference from rust tests during IDL generation ([#3058](https://github.com/coral-xyz/anchor/pull/3058)).
 - lang: Fix `align` repr support in `declare-program!` ([#3056](https://github.com/coral-xyz/anchor/pull/3056)).
+- lang: Make stack frames slimmer on ATA creation ([#3065](https://github.com/coral-xyz/anchor/pull/3065)).
 
 ### Breaking
 

+ 13 - 11
lang/syn/src/codegen/accounts/constraints.rs

@@ -624,17 +624,19 @@ fn generate_constraint_init_group(
                     if !#if_needed || owner_program == &anchor_lang::solana_program::system_program::ID {
                         #payer_optional_check
 
-                        let cpi_program = associated_token_program.to_account_info();
-                        let cpi_accounts = ::anchor_spl::associated_token::Create {
-                            payer: #payer.to_account_info(),
-                            associated_token: #field.to_account_info(),
-                            authority: #owner.to_account_info(),
-                            mint: #mint.to_account_info(),
-                            system_program: system_program.to_account_info(),
-                            token_program: #token_program.to_account_info(),
-                        };
-                        let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, cpi_accounts);
-                        ::anchor_spl::associated_token::create(cpi_ctx)?;
+                        ::anchor_spl::associated_token::create(
+                            anchor_lang::context::CpiContext::new(
+                                associated_token_program.to_account_info(),
+                                ::anchor_spl::associated_token::Create {
+                                    payer: #payer.to_account_info(),
+                                    associated_token: #field.to_account_info(),
+                                    authority: #owner.to_account_info(),
+                                    mint: #mint.to_account_info(),
+                                    system_program: system_program.to_account_info(),
+                                    token_program: #token_program.to_account_info(),
+                                }
+                            )
+                        )?;
                     }
                     let pa: #ty_decl = #from_account_info_unchecked;
                     if #if_needed {

+ 51 - 0
tests/misc/programs/misc-optional/src/context.rs

@@ -693,3 +693,54 @@ pub struct TestAssociatedTokenWithTokenProgramConstraint<'info> {
     /// CHECK: ignore
     pub associated_token_token_program: Option<AccountInfo<'info>>,
 }
+
+#[derive(Accounts)]
+pub struct InitManyAssociatedTokenAccounts<'info> {
+    #[account(
+        init,
+        payer = user,
+        mint::authority = user,
+        mint::decimals = 9,
+    )]
+    pub mint: Account<'info, Mint>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = user,
+        associated_token::mint = mint,
+    )]
+    pub ata1: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = system_program,
+        associated_token::mint = mint,
+    )]
+    pub ata2: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata3: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = associated_token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata4: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = mint,
+        associated_token::mint = mint,
+    )]
+    pub ata5: Account<'info, TokenAccount>,
+    #[account(mut)]
+    pub user: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+}

+ 7 - 0
tests/misc/programs/misc-optional/src/lib.rs

@@ -395,4 +395,11 @@ pub mod misc_optional {
     ) -> Result<()> {
         Ok(())
     }
+
+    #[allow(unused_variables)]
+    pub fn test_init_many_associated_token_accounts(
+        _ctx: Context<InitManyAssociatedTokenAccounts>,
+    ) -> Result<()> {
+        Ok(())
+    }
 }

+ 52 - 0
tests/misc/programs/misc/src/context.rs

@@ -601,6 +601,7 @@ pub struct TestOnlyTokenProgramConstraint<'info> {
         token::token_program = token_token_program
     )]
     pub token: Account<'info, TokenAccount>,
+    /// CHECK: ignore
     pub token_token_program: AccountInfo<'info>,
 }
 
@@ -751,3 +752,54 @@ pub struct TestUsedIdentifiers<'info> {
     /// CHECK: ignore
     pub test4: AccountInfo<'info>,
 }
+
+#[derive(Accounts)]
+pub struct InitManyAssociatedTokenAccounts<'info> {
+    #[account(
+        init,
+        payer = user,
+        mint::authority = user,
+        mint::decimals = 9,
+    )]
+    pub mint: Account<'info, Mint>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = user,
+        associated_token::mint = mint,
+    )]
+    pub ata1: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = system_program,
+        associated_token::mint = mint,
+    )]
+    pub ata2: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata3: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = associated_token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata4: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = mint,
+        associated_token::mint = mint,
+    )]
+    pub ata5: Account<'info, TokenAccount>,
+    #[account(mut)]
+    pub user: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+}

+ 7 - 0
tests/misc/programs/misc/src/lib.rs

@@ -385,4 +385,11 @@ pub mod misc {
     ) -> Result<()> {
         Ok(())
     }
+
+    #[allow(unused_variables)]
+    pub fn test_init_many_associated_token_accounts(
+        _ctx: Context<InitManyAssociatedTokenAccounts>,
+    ) -> Result<()> {
+        Ok(())
+    }
 }

+ 9 - 0
tests/misc/tests/misc/misc.ts

@@ -2451,6 +2451,15 @@ const miscTest = (
       assert.deepStrictEqual(dataAccount.data, array2d);
     });
 
+    it("Can initialize 5 associated token accounts in one instruction", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.methods
+        .testInitManyAssociatedTokenAccounts()
+        .accounts({ mint: mint.publicKey, user: provider.wallet.publicKey })
+        .signers([mint])
+        .rpc();
+    });
+
     describe("Can validate PDAs derived from other program ids", () => {
       it("With bumps using create_program_address", async () => {
         const [firstPDA, firstBump] =