2

I'm new to Solana and I'm trying to implement a multisig wallet with transfer SOL functionality. Basically I followed the implementation from this repo.

The problem is when I try to invoke my transfer function:

pub fn transfer_funds( ctx:Context<Transfer>,amount:u64) -> Result<()> {
  let amount_of_lamports = amount;
  let from = ctx.accounts.from.to_account_info();
  let to = ctx.accounts.to.to_account_info();

  **from.try_borrow_mut_lamports()? -= amount_of_lamports;
  **to.try_borrow_mut_lamports()? += amount_of_lamports;

  Ok(())
}

From the execute transaction function:

pub fn execute_transaction(ctx: Context<ExecuteTransaction>) -> Result<()> {
  msg!("Executing Transaction");
  if ctx.accounts.transaction.did_execute {
    return Err(ErrorCode::AlreadyExecuted.into());
  }

  let sig_count = ctx
    .accounts
    .transaction
    .signers
    .iter()
    .filter(|&did_sign| *did_sign)
    .count() as u64;

  if sig_count < ctx.accounts.wallet.threshold {
    return Err(ErrorCode::NotEnoughSigners.into());
  }

  let mut ix: Instruction = (*ctx.accounts.transaction).deref().into();
  ix.accounts = ix
    .accounts
    .iter()
    .map(|acc| {
      let mut acc = acc.clone();
      if &acc.pubkey == ctx.accounts.wallet_signer.key {
        acc.is_signer = true;
      }
      acc
    })
    .collect();

    let wallet_key = ctx.accounts.wallet.key();
    let seeds = &[wallet_key.as_ref(), &[ctx.accounts.wallet.nonce]];
    let signer = &[&seeds[..]];
    let accounts = ctx.remaining_accounts;
    solana_program::program::invoke_signed(&ix, accounts, signer)?;

    ctx.accounts.transaction.did_execute = true;
    emit!(TransactionExecutedEvent {
      wallet: ctx.accounts.wallet.key(),
      transaction: ctx.accounts.transaction.key(),
    });

    Ok(())
  }
}

I get the Error: Transaction simulation failed Error processing Instruction insufficient account keys for instruction

I can, without problems, execute the set_owners and change_threshold functions.

My transaction for the transfer looks like this:

const [walletSigner] = await web3.PublicKey.findProgramAddress(
  [new PublicKey(state.connection.msig).toBuffer()],
  state.connection.program.programId
);
let data;
try {
  data = state.connection.program.coder.instruction.encode(
    'transfer_funds',
    {
      amount: new BN(args.amount),
    },
  );
} catch (err) {
  console.log(err);
}

const accounts = [
  {
    pubkey: mustisigPublicKey,
    isWritable: true,
    isSigner: false,
  },
  {
    pubkey: walletSigner,
    isWritable: false,
    isSigner: true,
  },
];
const transaction = web3.Keypair.generate();
const tx = await state.connection.program.rpc.createTransferTransaction(
  state.connection.program.programId,
  accounts,
  data,
  {
    accounts: {
      wallet: mustisigPublicKey,
      transaction: transaction.publicKey,
      initiator: state.connection.provider.wallet.publicKey,
      to: args.to,
      from: mustisigPublicKey,
      systemProgram: web3.SystemProgram.programId,
    },
    instructions: [
      await state.connection.program.account.wallet.createInstruction(
        transaction,
        1000
      ),
    ],
    signers: [transaction],
  }
);

I'm guessing that this is related somehow to the accounts context not being forwarded to transfer function, but as I'm a complete beginner I cant be sure :/

1
  • I'm voting to close this question because it both contains too much and not enough clarity (eg. the definition of the Transfer struct is missing). If this is still relevant a year later, try to clarify the problem and give just enough detail for someone to spot the problem. Commented Dec 28, 2023 at 21:58

0

Browse other questions tagged or ask your own question.