From 40c048b74bb8f5f719edbcaa8b8b98a2d7a80fd1 Mon Sep 17 00:00:00 2001 From: Arrowana Date: Sun, 20 Oct 2024 20:55:31 +1100 Subject: [PATCH 1/2] fix: Client is_signer usage in to_account_metas --- lang/syn/src/codegen/accounts/__client_accounts.rs | 4 ++-- lang/syn/src/codegen/accounts/__cpi_client_accounts.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lang/syn/src/codegen/accounts/__client_accounts.rs b/lang/syn/src/codegen/accounts/__client_accounts.rs index 53c6fc9276..08ea8595e2 100644 --- a/lang/syn/src/codegen/accounts/__client_accounts.rs +++ b/lang/syn/src/codegen/accounts/__client_accounts.rs @@ -84,7 +84,7 @@ pub fn generate( AccountField::CompositeField(s) => { let name = &s.ident; quote! { - account_metas.extend(self.#name.to_account_metas(None)); + account_metas.extend(self.#name.to_account_metas(is_signer)); } } AccountField::Field(f) => { @@ -94,7 +94,7 @@ pub fn generate( }; let is_signer = match is_signer { false => quote! {false}, - true => quote! {true}, + true => quote! {is_signer.unwrap_or(true)}, }; let meta = match f.constraints.is_mutable() { false => quote! { anchor_lang::solana_program::instruction::AccountMeta::new_readonly }, diff --git a/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs b/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs index 5211e59305..06210b282a 100644 --- a/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs +++ b/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs @@ -85,7 +85,7 @@ pub fn generate( AccountField::CompositeField(s) => { let name = &s.ident; quote! { - account_metas.extend(self.#name.to_account_metas(None)); + account_metas.extend(self.#name.to_account_metas(is_signer)); } } AccountField::Field(f) => { @@ -95,7 +95,7 @@ pub fn generate( }; let is_signer = match is_signer { false => quote! {false}, - true => quote! {true}, + true => quote! {is_signer.unwrap_or(true)}, }; let meta = match f.constraints.is_mutable() { false => quote! { anchor_lang::solana_program::instruction::AccountMeta::new_readonly }, From d344355b7b4584564393cd4952a291cf747a06f1 Mon Sep 17 00:00:00 2001 From: Arrowana Date: Mon, 2 Dec 2024 21:51:43 +1100 Subject: [PATCH 2/2] add test to leverage is_signer --- .../programs/declare-program/Cargo.toml | 5 ++ .../programs/declare-program/src/lib.rs | 36 ++++++++++++ .../tests/declare_program_test.rs | 57 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 tests/declare-program/programs/declare-program/tests/declare_program_test.rs diff --git a/tests/declare-program/programs/declare-program/Cargo.toml b/tests/declare-program/programs/declare-program/Cargo.toml index a713247476..4127ff7cea 100644 --- a/tests/declare-program/programs/declare-program/Cargo.toml +++ b/tests/declare-program/programs/declare-program/Cargo.toml @@ -14,6 +14,11 @@ no-idl = [] cpi = ["no-entrypoint"] default = [] idl-build = ["anchor-lang/idl-build"] +test-sbf = [] [dependencies] anchor-lang = { path = "../../../../lang" } + +[dev-dependencies] +solana-sdk = "2" +solana-program-test = "2" \ No newline at end of file diff --git a/tests/declare-program/programs/declare-program/src/lib.rs b/tests/declare-program/programs/declare-program/src/lib.rs index dc6c36f8f6..45b00d58f0 100644 --- a/tests/declare-program/programs/declare-program/src/lib.rs +++ b/tests/declare-program/programs/declare-program/src/lib.rs @@ -8,8 +8,12 @@ use external::program::External; // Compilation check for legacy IDL (pre Anchor `0.30`) declare_program!(external_legacy); +pub const GLOBAL: &[u8] = b"global"; + #[program] pub mod declare_program { + use anchor_lang::solana_program::{instruction::Instruction, program::invoke_signed}; + use super::*; pub fn cpi(ctx: Context, value: u32) -> Result<()> { @@ -114,6 +118,33 @@ pub mod declare_program { Ok(()) } + + pub fn proxy(ctx: Context, data: Vec) -> Result<()> { + let (authority, bump) = Pubkey::find_program_address(&[GLOBAL], &ID); + + let accounts = ctx + .remaining_accounts + .iter() + .map(|ra| AccountMeta { + pubkey: ra.key(), + is_signer: ra.is_signer || &authority == ra.key, + is_writable: ra.is_writable, + }) + .collect(); + + let signer_seeds: &[&[&[u8]]] = &[&[GLOBAL, &[bump]]]; + invoke_signed( + &Instruction { + program_id: ctx.accounts.program.key(), + accounts, + data, + }, + ctx.remaining_accounts, + signer_seeds, + )?; + + Ok(()) + } } #[derive(Accounts)] @@ -128,3 +159,8 @@ pub struct Cpi<'info> { pub struct Utils<'info> { pub authority: Signer<'info>, } + +#[derive(Accounts)] +pub struct Proxy<'info> { + pub program: Program<'info, External>, +} diff --git a/tests/declare-program/programs/declare-program/tests/declare_program_test.rs b/tests/declare-program/programs/declare-program/tests/declare_program_test.rs new file mode 100644 index 0000000000..74b1d1910b --- /dev/null +++ b/tests/declare-program/programs/declare-program/tests/declare_program_test.rs @@ -0,0 +1,57 @@ +#![cfg(feature = "test-sbf")] + +use solana_sdk::{ + native_token::LAMPORTS_PER_SOL, signature::Signer, system_instruction, transaction::Transaction, +}; +use { + anchor_lang::{ + prelude::Pubkey, + solana_program::{instruction::Instruction, system_program}, + InstructionData, ToAccountMetas, + }, + declare_program::external, + solana_program_test::{tokio, ProgramTest}, +}; + +#[tokio::test] +async fn proxy() { + let mut pt = ProgramTest::new("declare_program", declare_program::id(), None); + pt.add_program("external", external::ID, None); + + let (banks_client, payer, recent_blockhash) = pt.start().await; + + let authority = + Pubkey::find_program_address(&[declare_program::GLOBAL], &declare_program::ID).0; + let mut accounts = declare_program::accounts::Proxy { + program: external::ID, + } + .to_account_metas(None); + accounts.extend( + external::client::accounts::Init { + authority, + my_account: Pubkey::find_program_address(&[authority.as_ref()], &external::ID).0, + system_program: system_program::ID, + } + .to_account_metas(Some(false)), // Forward as remaining accounts but toggle authority not to be a signer + ); + + let data = declare_program::instruction::Proxy { + data: external::client::args::Init {}.data(), + } + .data(); + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::transfer(&payer.pubkey(), &authority, LAMPORTS_PER_SOL), + Instruction { + program_id: declare_program::ID, + accounts, + data, + }, + ], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + + banks_client.process_transaction(transaction).await.unwrap(); +}