I'm trying to build an app that will hold a user's wallet private key to sign for transactions and pay for the account from a centralized wallet that I own. I'm trying to avoid them having to approve every transaction in their wallet. I want their wallet to be associated so I can restrict edits to it and to associate it the data to them however, I want to pay for the transaction from a centralized wallet. I'm stuck however and could use some help.
Here's the error I'm getting. I think I understand that the problem is coming from the PDA addresses aren't the same but, I'm stuck... Thanks in advance!
Error: AnchorError caused by account: new_account. Error Code: ConstraintSeeds. Error Number: 2006. Error Message: A seeds constraint was violated. Program log: Left: Program log: AhrfSUPi2gFzLX5v9BjYKid3BF6cGXw3JZCBFBAHj1Wm Program log: Right: Program log: CcjK29oCeU3D3Wf2BHdcXgKngVpmmgNnK5BveekWxEqz
Here's my code.
use anchor_lang::prelude::*;
pub mod constants;
pub mod states;
use crate::{constants::*, states::*};
declare_id!("4xNpqEwbZ5HhdXWWyg3NwEcVz4STahhbcHZwE1EAwNtq");
#[program]
mod terrapin_station {
use super::*;
pub fn initialize(ctx: Context<Initialize>, data: u64, bump: u8) -> Result<()> {
ctx.accounts.new_account.data = data;
ctx.accounts.new_account.bump = bump;
msg!("Changed data to: {}!", data);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init,
payer = payer,
space = 8 + 8 + 1,
seeds = [DEAD_CASTER, new_account.key().as_ref()],
bump)]
pub new_account: Account<'info, NewAccount>,
#[account(mut)]
pub signer: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}
states.rs
use anchor_lang::prelude::*;
#[account]
pub struct NewAccount {
pub data: u64,
pub bump: u8,
}
constants.rs
use anchor_lang::prelude::*;
#[constant]
pub const DEAD_CASTER: &[u8] = b"dead_caster";
My Test looks like this.
import * as anchor from "@coral-xyz/anchor";
import { Program, AnchorProvider, BN } from "@coral-xyz/anchor";
import { utf8 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"
import { PublicKey, Keypair } from "@solana/web3.js";
import { TerrapinStation } from "../target/types/terrapin_station";
import fs from 'fs';
import path from 'path';
const loadKeypairFromFile = (filePath: string): Keypair => {
const keypairString = fs.readFileSync(filePath, 'utf8');
const secretKey = Uint8Array.from(JSON.parse(keypairString));
return Keypair.fromSecretKey(secretKey);
};
describe("terrapin-station", () => {
const keypairPath = '/Users/chris/.config/solana/terra-test.json';
const provider = AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.TerrapinStation as Program<TerrapinStation>;
let newAccount: Keypair;
let deadcasterAddress: PublicKey;
let bump: number;
before(async () => {
// Load the payer keypair
const payer = loadKeypairFromFile(path.resolve(__dirname, keypairPath));
// Generate a new keypair for the new account
newAccount = Keypair.generate();
// Derive PDA using a static string and the new account's public key
[deadcasterAddress, bump] = PublicKey.findProgramAddressSync(
[utf8.encode('dead_caster'), newAccount.publicKey.toBuffer()],
program.programId
);
console.log("Derived PDA:", deadcasterAddress.toString(), "Bump:", bump);
});
it("Create a new account", async () => {
const payer = loadKeypairFromFile(path.resolve(__dirname, keypairPath));
// Create the transaction to initialize the new account
const tx = await program.methods.initialize(new BN(42), bump)
.accounts({
newAccount: deadcasterAddress,
signer: newAccount.publicKey,
payer: payer.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.signers([payer, newAccount])
.rpc();
console.log("Transaction signature for initialization:", tx);
});
it("Find the created account", async () => {
// Fetch the account data using the derived PDA
const accountData = await program.account.newAccount.fetch(deadcasterAddress);
console.log(`Fetched account data: ${accountData.data}`);
});
});