I want to test the anchor "has one" authority check so that only the signer that initialized the account can call a function in the smart contract. This way only the wallet that called the initialize function and created the storage account that holds the integer can then later call the increment function and change the integer.
Here is an excerpt of my contract:
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let account: &mut Account<CounterAccount>
= &mut ctx.accounts.counter_account;
account.count_number = 0;
return Ok(());
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let account: &mut Account<CounterAccount>
= &mut ctx.accounts.counter_account;
account.count_number += 1;
return Ok(());
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut, has_one = authority)]
counter_account: Account<'info, CounterAccount>,
authority: Signer<'info>
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer=authority, space=64)]
counter_account: Account<'info, CounterAccount>,
#[account(mut)]
authority: Signer<'info>,
system_program: Program<'info, System>
}
#[account]
pub struct CounterAccount {
count_number: i64,
authority: Pubkey,
}
Basically the increment function will not increment unless the the signer is the same as the stored authority pubkey in the CounterAccount struct stored when the CounterAccount in initialized in the initialized function. This is due to the has one check #[account(mut, has_one = authority)]
Here is the test so far, which initializes the account but fails at the increment test because the signer is unknown or error.
const anchor = require("@project-serum/anchor");
const assert = require("assert");
const { SystemProgram } = anchor.web3;
describe("test", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.Test;
const counterAccount = anchor.web3.Keypair.generate();
const signer = counterAccount;
//this passes and the account is initialized
it("Is initialized!", async () => {
const tx = await program.rpc
.initialize(
{
accounts: {
counterAccount: counterAccount.publicKey,
authority: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
},
signers: [signer]
}
);
console.log("Your transaction signature", tx);
const account = await program.account.counterAccount
.fetch(counterAccount.publicKey);
console.log('Count 0: ', account.countNumber)
assert.ok(account.countNumber == 0);
// Store the account for the next test.
_counterAccount = counterAccount;
});
Even if I add the authority account attribute and try different values for authority and signer,
it('increments account counter', async () => {
const counterAccount = _counterAccount;
await program.methods
.increment()
.accounts({
counterAccount: counterAccount.publicKey,
authority: signer.publicKey,
})
.signers([signer])
.rpc();
const account = await program.account.counterAccount
.fetch(counterAccount.publicKey);
assert.ok(account.countNumber.eq(new anchor.BN(1)));
})
the error is Error: AnchorError caused by account: counter_account. Error Code: ConstraintHasOne. Error Number: 2001. Error Message: A has one constraint was violated. Program log: Left: Program log: 11111111111111111111111111111111 Program log: Right: Program log: FxBGVvyUEumS9LzwWnmnpAnFr8joxjprDnHewXH1jNWj
How can I cause the signer to be the same as initialized so that the increment test will pass and has_one check will be fixed?