Browse Source

lang: Implement ToAccountMetas for CpiContext (#351)

Armani Ferrante 4 years ago
parent
commit
c23a5dfa29
3 changed files with 23 additions and 4 deletions
  1. 4 2
      CHANGELOG.md
  2. 17 0
      lang/src/context.rs
  3. 2 2
      lang/syn/src/codegen/program/cpi.rs

+ 4 - 2
CHANGELOG.md

@@ -11,6 +11,10 @@ incremented for features.
 
 ## [Unreleased]
 
+### Fixes
+
+* lang: Allows one to use `remaining_accounts` with `CpiContext` by implementing the `ToAccountMetas` trait on `CpiContext` ([#351](https://github.com/project-serum/anchor/pull/351/files)).
+
 ## [0.7.0] - 2021-05-31
 
 ### Features
@@ -31,8 +35,6 @@ incremented for features.
 * lang: Associated constraints no longer automatically implement `mut` ([#341](https://github.com/project-serum/anchor/pull/341)).
 * lang: Associated `space` constraints must now be literal integers instead of literal strings ([#341](https://github.com/project-serum/anchor/pull/341)).
 
-### Fixes
-
 ## [0.6.0] - 2021-05-23
 
 ### Features

+ 17 - 0
lang/src/context.rs

@@ -85,6 +85,23 @@ impl<'info, T: Accounts<'info>> ToAccountInfos<'info> for CpiContext<'_, '_, '_,
     }
 }
 
+impl<'info, T: Accounts<'info>> ToAccountMetas for CpiContext<'_, '_, '_, 'info, T> {
+    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
+        let mut metas = self.accounts.to_account_metas(is_signer);
+        metas.append(
+            &mut self
+                .remaining_accounts
+                .iter()
+                .map(|acc| match acc.is_writable {
+                    false => AccountMeta::new_readonly(*acc.key, acc.is_signer),
+                    true => AccountMeta::new(*acc.key, acc.is_signer),
+                })
+                .collect(),
+        );
+        metas
+    }
+}
+
 /// Context specifying non-argument inputs for cross-program-invocations
 /// targeted at program state instructions.
 pub struct CpiStateContext<'a, 'b, 'c, 'info, T: Accounts<'info>> {

+ 2 - 2
lang/syn/src/codegen/program/cpi.rs

@@ -80,14 +80,14 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
                                 .map_err(|_| ProgramError::InvalidInstructionData)?;
                             let mut data = #sighash_tts.to_vec();
                             data.append(&mut ix_data);
-                            let accounts = ctx.accounts.to_account_metas(None);
+                            let accounts = ctx.to_account_metas(None);
                             anchor_lang::solana_program::instruction::Instruction {
                                 program_id: *ctx.program.key,
                                 accounts,
                                 data,
                             }
                         };
-                        let mut acc_infos = ctx.accounts.to_account_infos();
+                        let mut acc_infos = ctx.to_account_infos();
                         acc_infos.push(ctx.program.clone());
                         anchor_lang::solana_program::program::invoke_signed(
                             &ix,