1

I am trying to create a simple swap contract.

The part of the swap function is like this:

    // Transfer tokens from user to pool
        let cpi_accounts_in = token::Transfer {
            from: ctx.accounts.user_token_in.to_account_info(),
            to: ctx.accounts.pool_token_in.to_account_info(),
            authority: ctx.accounts.user.to_account_info(), // User must authorize this transfer
        };
        let cpi_ctx_in = CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            cpi_accounts_in,
        );
        token::transfer(cpi_ctx_in, amount_in)?;
    
        // Transfer tokens from pool to user
        let cpi_accounts_out = token::Transfer {
            from: ctx.accounts.pool_token_out.to_account_info(),
            to: ctx.accounts.user_token_out.to_account_info(),
            authority: ctx.accounts.pool.to_account_info(), // Pool must be the authority for this transfer
        };
        let cpi_ctx_out = CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            cpi_accounts_out,
        );
        token::transfer(cpi_ctx_out, output_amount)?;

As you can see, there are 2 different authorities.

However, in the TS test code I have somehting like this:

    const tx = await program.methods
          .swap(new anchor.BN(swapAmountIn), new anchor.BN(minAmountOut))
          .accounts({
            pool: pool.publicKey,
            userTokenIn: userTokenAccountA,
            userTokenOut: userTokenAccountB,
            poolTokenIn: poolTokenAccountA,
            poolTokenOut: poolTokenAccountB,
            user: payer.publicKey,
            tokenProgram: TOKEN_PROGRAM_ID,
          })
          .signers([payer])
          .rpc();

Since in this code, I am providing only 1 signer, I am getting this error during anchor test:

    Simulation failed.
    Message: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account.
    Logs:
    [
      "Program E7nE9N9yiLHhMZDdD9U7duT8SKuiUVLhkE7WJkSwSpkt invoke [1]",
      "Program log: Instruction: Swap",
      "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]",
      "Program log: Instruction: Transfer",
      "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 188115 compute units",
      "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
      "7hGVDEXUfomYMppU7ibSzEvTwgFMg9SWBfrGaWJSY5dL's signer privilege escalated",
      "Program E7nE9N9yiLHhMZDdD9U7duT8SKuiUVLhkE7WJkSwSpkt consumed 18859 of 200000 compute units",
      "Program E7nE9N9yiLHhMZDdD9U7duT8SKuiUVLhkE7WJkSwSpkt failed: Cross-program invocation with unauthorized signer or writable account"
    ].

Is there any way I can provide both the signers (user and pool) in the test code? Or maybe there is a better and neat solution that I am missing? Thanks!

New contributor
zubayr khalid is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

1 Answer 1

1

Make sure that the pool is marked as a singer in your [derive(Accounts)] struct

#[derive(Accounts)]
pub struct MyAccounts<'info> {
  #[account(mut)]
  pub pool: Signer<'info>,
}

Pass the pool keypair on the client side as part of the signers array

.signers([payer, pool])
1
  • 1
    Thanks a lot. I spent 1 whole evening searching for this answer Commented Sep 5 at 8:01

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.