2

I have a this function

pub fn sign_up(ctx: Context<SignUp> , user_name: String , phone_number: String , email: String) -> Result<()> {// logic is here}

And in SignUp i have :

#[derive(Accounts)]
#[instruction(user_name: String , phone_number: String , email: String)]
pub struct SignUp<'info> {
#[account(init,
    seeds = [b"user-account".as_ref(), authority.key().as_ref() , user_name.as_bytes() , email.as_bytes() , phone_number.as_bytes()   ],bump,
          payer = authority, 
          space = size_of::<UserAccount>() + USER_NAME_LENGTH + EMAIL_LENGTH + NAME_LENGTH + PHONE_NUMBER_LENGTH + 8 + 8 + 2 + 2 )]
pub user: Account<'info, UserAccount>,

// Associated user with the smart contract who paid transaction fee 
/// CHECK: only used as a signing PDA
#[account(mut)]
pub authority: Signer<'info>,

// It's the smart contract that we have 
pub system_program: Program<'info , System>,
pub clock: Sysvar<'info , Clock>
}

And my goal is to

first : validate the user that is being created to have unique username , phone_number and email

second : to sign the account creation with PDA .

I have wrriten a test (and i know i'm not using PDA because i don't know how ) and It does not work and fails with : Error: unknown signer: 7FiB... error and my test code is this :

        let [userAccountPDA, _] = await anchor.web3.PublicKey
    .findProgramAddress(
      [
        anchor.utils.bytes.utf8.encode("user-account"),
        user.publicKey.toBuffer(),
        anchor.utils.bytes.utf8.encode("reasje"),
        anchor.utils.bytes.utf8.encode("09146979106"),
        anchor.utils.bytes.utf8.encode(""),
      ],
      program.programId
    );
    
    await program.methods.signUp("reasje", "09146979106", "").accounts({
        user: user.publicKey,
        authority: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
        clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
    }).signers([user]).rpc();

2 Answers 2

2

I'm not sure what exactly you mean by "signing PDA".

A PDA is a program-derived address that by definition is off the cure, so it doesn't have a private key and therefor cannot sign anything.

However, the cool thing about PDAs is that the program that the PDA is derived from can use invoke_signed which will then be handled by the Solana runtime as if the PDA had signed the transaction.

Not really sure about what you're trying to achieve here, but I guess your SignUp instruction is supposed to create (and initialize) the PDA account.

So when someone signs up, you create a Solana account ("data record") for them where their data is stored, and the Solana address you use for this "data record" will be a PDA (program-derived address), not a wallet address.

So I suggest to update your code like this:

#[derive(Accounts)]
#[instruction(user_name: String , phone_number: String , email: String)]
pub struct SignUp<'info> {
#[account(init,
    seeds = [b"user-account".as_ref(), user.key().as_ref() , user_name.as_bytes() , email.as_bytes() , phone_number.as_bytes()   ],bump,
          payer = user, 
          space = size_of::<UserAccount>() + USER_NAME_LENGTH + EMAIL_LENGTH + NAME_LENGTH + PHONE_NUMBER_LENGTH + 8 + 8 + 2 + 2 )]
pub userdata: Account<'info, UserAccount>, // PDA where data is stored

// Associated user with the smart contract who paid transaction fee 
/// CHECK: only used as a fee payer
#[account(signer)]
pub user: AccountInfo<'info>, // user's wallet address, used to pay fee

// It's the smart contract that we have 
pub system_program: Program<'info , System>,
pub clock: Sysvar<'info , Clock>
}

I'm not sure if you really need the user name, phone number, email as part of the seed. The user's wallet address should be unique, so there is probably no need to include the user data fields. But you might have your reasons, and either way it doesn't hurt.

Then the JS test code would look like this:

let [userAccountPDA, _] = await anchor.web3.PublicKey
    .findProgramAddress(
      [
        anchor.utils.bytes.utf8.encode("user-account"),
        user.publicKey.toBuffer(),
        anchor.utils.bytes.utf8.encode("reasje"),
        anchor.utils.bytes.utf8.encode("09146979106"),
        anchor.utils.bytes.utf8.encode(""),
      ],
      program.programId
    );
    
    await program.methods.signUp("reasje", "09146979106", "").accounts({
        userdata: userAccountPDA,
        user: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
        clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
    }).rpc();

No .signers([user]) needed because the user is declared as #[account(signer)] in Anchor.

Let me know if that solves your issue.

1
  • Thanks for the answer and yes you understood my questions pretty well . I have updated my code with your changes but I'm getting Cross-program invocation with unauthorized signer or writable account error . Should i use invoke_signed to solve this problem ? Aug 7, 2022 at 4:48
1

I see you have already created a PDA, but have not used it in the instruction

You can pass the PDA like this

 await program.methods.signUp("reasje", "09146979106", "").accounts({
        user: userAccountPDA,
        authority: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
        clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
    }).rpc();

And i have also noticed you are encoding "" in your PDA creation, while it should be like this

let [userAccountPDA, _] = await anchor.web3.PublicKey
.findProgramAddress(
  [
    anchor.utils.bytes.utf8.encode("user-account"),
    user.publicKey.toBuffer(),
    anchor.utils.bytes.utf8.encode("reasje"),
    anchor.utils.bytes.utf8.encode("09146979106"),
    // No need for this line, anchor.utils.bytes.utf8.encode("")
  ],


program.programId
);

The error you are getting is related to the fact that you are passing user as signer, which in fact is not needed. Hence removing the signer argument would eliminate it.

You can read more on PDA here PDA - Anchor Book

1
  • Thanks for the answer, but the code is not working with Cross-program invocation with unauthorized signer or writable account error . Do I need to put invoke_signed or any other code in sign_up function ? Aug 10, 2022 at 7:10

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.