2

I'm kinda confused on how ownership and signing works in Solana/Anchor, like if I create a user like this:

#[derive(Accounts)]
pub struct InitializeUser<'info> {
    #[account(
        init,
        payer = signer,
        space = 8 + UserAccount::INIT_SPACE,
        seeds = [b"USER", signer.key().as_ref()],
        bump
    )]
    pub user: Account<'info, UserAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

and the call to create it from the client:

const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);

const program = anchor.workspace.myProgram as anchor.Program<MyProgram>;

const userKp = anchor.web3.Keypair.generate();
const userPubkey = userKp.publicKey;

const _tx = await program.methods
   .initializeUser(some_data)
   .accounts({
     signer: userPubkey,
   })
   .signers([userKp])
   .rpc();

At this point I'm specifying that the signer of the transaction is some wallet, but not the program itself, so who is the owner (or can there be multiple)? And who can change the data of the UserAccount just created, is it just the owner that can do it?

Like the following Account restricts that the signer of the transaction will be able to change only the PDA derived from its address because it's how we are calculating it:

#[derive(Accounts)]
pub struct UpdateUser<'info> {
    #[account(
        mut,
        seeds = [b"USER", signer.key().as_ref()],
        bump
    )]
    pub user: Account<'info, UserAccount>,
    #[account(mut)]
    pub signer: Signer<'info>
}

How can I change this so that the wallet that created the account or the program that the account was derived from can change its data? For example, in this case if I wanted to modify another user's account I'd have to issue a request for their signature, but I'd like a way to select who can change the data, without needing to require permission.

1 Answer 1

1

There are some issues with the client code you shared,

This part here sets your local wallet as the signer, and calling your instruction with .rpc will use this wallet to sign the transaction being sent.

const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);

Thus, makes this part .signers([userKp]) wrong as userKP is a PDA that isn't declared as a signer in the original InitializeUser context.

In the code snippet you shared, you are also wrongly deriving the user PDA. A PDA is an address that doesn't have a corresponding secret key, as such you do not need to generate a new Keypair, but find/derive using the seeds and program that will own the account.

This can be accomplished using the findProgramAddressSync method

findProgramAddressSync(
        [
            SEEDS(byte array)
        ],
        PROGRAM_ID
    ) 

You might also need to update the account too with the correct account order, though Anchor 30 does automatic account resolution, I think it's personal to be as explicit as possible

const userPDA = PublicKey.findProgramAddressSync(
        [Buffer.from("user"), provider.publicKey.toBuffer()],
            program.programId
    )[0];

const _tx = await program.methods
   .initializeUser(some_data)
   .accounts({
     signer: provider.publicKey,
     user: userPDA # derived user pda
     systemProgram: SystemProgram.programId,

   })
   .rpc();

In the UpdateUser context, anyone can call this method and update the account data depending on how you've defined the instruction method.

To limit the addresses that can call this you can use the address constraint to limit this

#[derive(Accounts)]
pub struct UpdateUser<'info> {
    #[account(
        mut,
    )]
    pub user: Account<'info, UserAccount>,
    #[account(mut, address = "11111111111111111111111111111111")] # only the system program is allowed to call this IX. update with the preferred address
    pub signer: Signer<'info>
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.