From 9331908aeea717fdfaa144325cb01c5434409ea6 Mon Sep 17 00:00:00 2001 From: Pierre Date: Thu, 26 Oct 2023 10:14:38 +1100 Subject: [PATCH] tests: Add remaining accounts test (#2683) --- tests/misc/Anchor.toml | 1 + tests/misc/programs/misc-optional/Cargo.toml | 4 +- tests/misc/programs/misc/Cargo.toml | 4 +- .../programs/remaining-accounts/Cargo.toml | 20 ++++ .../programs/remaining-accounts/Xargo.toml | 2 + .../remaining-accounts/src/account.rs | 11 ++ .../remaining-accounts/src/context.rs | 26 ++++ .../programs/remaining-accounts/src/lib.rs | 42 +++++++ tests/misc/tests/remaining-accounts/Test.toml | 2 + .../remaining-accounts/remaining-accounts.ts | 111 ++++++++++++++++++ 10 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 tests/misc/programs/remaining-accounts/Cargo.toml create mode 100644 tests/misc/programs/remaining-accounts/Xargo.toml create mode 100644 tests/misc/programs/remaining-accounts/src/account.rs create mode 100644 tests/misc/programs/remaining-accounts/src/context.rs create mode 100644 tests/misc/programs/remaining-accounts/src/lib.rs create mode 100644 tests/misc/tests/remaining-accounts/Test.toml create mode 100644 tests/misc/tests/remaining-accounts/remaining-accounts.ts diff --git a/tests/misc/Anchor.toml b/tests/misc/Anchor.toml index e4990e1ca..d5eace4c7 100644 --- a/tests/misc/Anchor.toml +++ b/tests/misc/Anchor.toml @@ -7,6 +7,7 @@ init_if_needed = "BZoppwWi6jMnydnUBEJzotgEXHwLr3b3NramJgZtWeF2" lamports = "Lamports11111111111111111111111111111111111" misc = "3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh" misc_optional = "FNqz6pqLAwvMSds2FYjR4nKV3moVpPNtvkfGFrqLKrgG" +remaining_accounts = "RemainingAccounts11111111111111111111111111" [workspace] exclude = ["programs/shared"] diff --git a/tests/misc/programs/misc-optional/Cargo.toml b/tests/misc/programs/misc-optional/Cargo.toml index 2461dc268..366cc8d1c 100644 --- a/tests/misc/programs/misc-optional/Cargo.toml +++ b/tests/misc/programs/misc-optional/Cargo.toml @@ -18,5 +18,5 @@ default = [] [dependencies] anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] } anchor-spl = { path = "../../../../spl" } -spl-associated-token-account = "1.1.1" -bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]} +spl-associated-token-account = { version = "1.1.1", features = ["no-entrypoint"] } +bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] } diff --git a/tests/misc/programs/misc/Cargo.toml b/tests/misc/programs/misc/Cargo.toml index 530b77f38..caa7507ba 100644 --- a/tests/misc/programs/misc/Cargo.toml +++ b/tests/misc/programs/misc/Cargo.toml @@ -18,5 +18,5 @@ default = [] [dependencies] anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] } anchor-spl = { path = "../../../../spl" } -spl-associated-token-account = "1.1.1" -bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]} +spl-associated-token-account = { version = "1.1.1", features = ["no-entrypoint"] } +bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] } diff --git a/tests/misc/programs/remaining-accounts/Cargo.toml b/tests/misc/programs/remaining-accounts/Cargo.toml new file mode 100644 index 000000000..19f2010d5 --- /dev/null +++ b/tests/misc/programs/remaining-accounts/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "remaining-accounts" +version = "0.1.0" +description = "Created with Anchor" +rust-version = "1.60" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "remaining_accounts" + +[features] +no-entrypoint = [] +no-idl = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] } +anchor-spl = { path = "../../../../spl" } diff --git a/tests/misc/programs/remaining-accounts/Xargo.toml b/tests/misc/programs/remaining-accounts/Xargo.toml new file mode 100644 index 000000000..1744f098a --- /dev/null +++ b/tests/misc/programs/remaining-accounts/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/tests/misc/programs/remaining-accounts/src/account.rs b/tests/misc/programs/remaining-accounts/src/account.rs new file mode 100644 index 000000000..7ab4eb298 --- /dev/null +++ b/tests/misc/programs/remaining-accounts/src/account.rs @@ -0,0 +1,11 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct Data { + pub someone: Pubkey, +} + +#[account] +#[derive(InitSpace)] +pub struct Another {} diff --git a/tests/misc/programs/remaining-accounts/src/context.rs b/tests/misc/programs/remaining-accounts/src/context.rs new file mode 100644 index 000000000..a17f3ed61 --- /dev/null +++ b/tests/misc/programs/remaining-accounts/src/context.rs @@ -0,0 +1,26 @@ +use crate::account::*; +use anchor_lang::prelude::*; +use anchor_spl::token::Token; + +#[derive(Accounts)] +pub struct TestInit<'info> { + #[account(init, payer = payer, space = Data::INIT_SPACE + 8)] + pub data: Account<'info, Data>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct TestInitAnother<'info> { + #[account(init, payer = payer, space = Data::INIT_SPACE + 8)] + pub another: Account<'info, Another>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct TestRemainingAccounts<'info> { + pub token_program: Program<'info, Token>, +} diff --git a/tests/misc/programs/remaining-accounts/src/lib.rs b/tests/misc/programs/remaining-accounts/src/lib.rs new file mode 100644 index 000000000..b93b91fd4 --- /dev/null +++ b/tests/misc/programs/remaining-accounts/src/lib.rs @@ -0,0 +1,42 @@ +//! Testing of handling of remaining accounts with anchor Account structs + +use account::*; +use anchor_lang::prelude::*; +use anchor_spl::token::TokenAccount; +use context::*; + +mod account; +mod context; + +declare_id!("RemainingAccounts11111111111111111111111111"); + +#[program] +pub mod remaining_accounts { + use super::*; + + pub fn test_init(_ctx: Context) -> Result<()> { + Ok(()) + } + + pub fn test_init_another(_ctx: Context) -> Result<()> { + Ok(()) + } + + pub fn test_remaining_accounts<'c: 'info, 'info>( + ctx: Context<'_, '_, 'c, 'info, TestRemainingAccounts>, + ) -> Result<()> { + let remaining_accounts_iter = &mut ctx.remaining_accounts.iter(); + + let token_account = + Account::::try_from(next_account_info(remaining_accounts_iter)?)?; + + let data_account_info = next_account_info(remaining_accounts_iter)?; + require_eq!(data_account_info.is_writable, true); + let mut data = Account::::try_from(data_account_info)?; + + data.someone = token_account.owner; + data.exit(ctx.program_id)?; + + Ok(()) + } +} diff --git a/tests/misc/tests/remaining-accounts/Test.toml b/tests/misc/tests/remaining-accounts/Test.toml new file mode 100644 index 000000000..34c1c9052 --- /dev/null +++ b/tests/misc/tests/remaining-accounts/Test.toml @@ -0,0 +1,2 @@ +[scripts] +test = "yarn run ts-mocha -t 1000000 ./tests/remaining-accounts/*.ts" diff --git a/tests/misc/tests/remaining-accounts/remaining-accounts.ts b/tests/misc/tests/remaining-accounts/remaining-accounts.ts new file mode 100644 index 000000000..7a9fc9009 --- /dev/null +++ b/tests/misc/tests/remaining-accounts/remaining-accounts.ts @@ -0,0 +1,111 @@ +import * as anchor from "@coral-xyz/anchor"; + +import { TOKEN_PROGRAM_ID, Token } from "@solana/spl-token"; +import { assert } from "chai"; +import { RemainingAccounts, IDL } from "../../target/types/remaining_accounts"; +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; + +describe(IDL.name, () => { + // Configure the client to use the local cluster + anchor.setProvider(anchor.AnchorProvider.env()); + const payer = NodeWallet.local().payer; + + const program = anchor.workspace + .RemainingAccounts as anchor.Program; + + it("Account can be used with remaining accounts - read token account and write someone to Data", async () => { + const data = anchor.web3.Keypair.generate(); + await program.methods + .testInit() + .accounts({ data: data.publicKey }) + .signers([data]) + .rpc(); + const ata = await Token.createWrappedNativeAccount( + program.provider.connection, + TOKEN_PROGRAM_ID, + payer.publicKey, + payer, + 0 + ); + + // Data is not initialized + try { + await program.methods + .testRemainingAccounts() + .accounts({ + tokenProgram: TOKEN_PROGRAM_ID, + }) + .remainingAccounts([ + { pubkey: ata, isSigner: false, isWritable: false }, + { + pubkey: anchor.web3.Keypair.generate().publicKey, + isSigner: false, + isWritable: true, + }, + ]) + .rpc(); + assert.isTrue(false); + } catch (_err) { + assert.isTrue(_err instanceof anchor.AnchorError); + const err: anchor.AnchorError = _err; + assert.strictEqual(err.error.errorCode.number, 3012); + assert.strictEqual(err.error.errorCode.code, "AccountNotInitialized"); + } + + // Can read and write from account infos from remaining_accounts + await program.methods + .testRemainingAccounts() + .accounts({ + tokenProgram: TOKEN_PROGRAM_ID, + }) + .remainingAccounts([ + { pubkey: ata, isSigner: false, isWritable: false }, + { + pubkey: data.publicKey, + isSigner: false, + isWritable: true, + }, + ]) + .rpc(); + + const dataAccount = await program.account.data.fetch(data.publicKey); + assert.strictEqual( + dataAccount.someone.toString(), + payer.publicKey.toString() + ); + + // Another account + const another = anchor.web3.Keypair.generate(); + await program.methods + .testInitAnother() + .accounts({ another: another.publicKey }) + .signers([another]) + .rpc(); + + try { + await program.methods + .testRemainingAccounts() + .accounts({ + tokenProgram: TOKEN_PROGRAM_ID, + }) + .remainingAccounts([ + { pubkey: ata, isSigner: false, isWritable: false }, + { + pubkey: another.publicKey, + isSigner: false, + isWritable: true, + }, + ]) + .rpc(); + assert.isTrue(false); + } catch (_err) { + assert.isTrue(_err instanceof anchor.AnchorError); + const err: anchor.AnchorError = _err; + assert.strictEqual(err.error.errorCode.number, 3002); + assert.strictEqual( + err.error.errorCode.code, + "AccountDiscriminatorMismatch" + ); + } + }); +});