tests: Add remaining accounts test (#2683)

This commit is contained in:
Pierre 2023-10-26 10:14:38 +11:00 committed by GitHub
parent 85a5a9bdfc
commit 9331908aee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 219 additions and 4 deletions

View File

@ -7,6 +7,7 @@ init_if_needed = "BZoppwWi6jMnydnUBEJzotgEXHwLr3b3NramJgZtWeF2"
lamports = "Lamports11111111111111111111111111111111111"
misc = "3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh"
misc_optional = "FNqz6pqLAwvMSds2FYjR4nKV3moVpPNtvkfGFrqLKrgG"
remaining_accounts = "RemainingAccounts11111111111111111111111111"
[workspace]
exclude = ["programs/shared"]

View File

@ -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"] }

View File

@ -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"] }

View File

@ -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" }

View File

@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []

View File

@ -0,0 +1,11 @@
use anchor_lang::prelude::*;
#[account]
#[derive(InitSpace)]
pub struct Data {
pub someone: Pubkey,
}
#[account]
#[derive(InitSpace)]
pub struct Another {}

View File

@ -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>,
}

View File

@ -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<TestInit>) -> Result<()> {
Ok(())
}
pub fn test_init_another(_ctx: Context<TestInitAnother>) -> 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::<TokenAccount>::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::<Data>::try_from(data_account_info)?;
data.someone = token_account.owner;
data.exit(ctx.program_id)?;
Ok(())
}
}

View File

@ -0,0 +1,2 @@
[scripts]
test = "yarn run ts-mocha -t 1000000 ./tests/remaining-accounts/*.ts"

View File

@ -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<RemainingAccounts>;
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"
);
}
});
});