I have this code to transfer sol via a contract and via web3 in ReactJS -
const transferSol = async () => { if (!publicKey) throw new WalletNotConnectedError(); const programId = new PublicKey('7XyzLTMw7nBzoZnYoxauCzv11ruJee3HqjbxCyDfYb52'); //transfer sol const { context: { slot: minContextSlot }, value: { blockhash, lastValidBlockHeight } } = await connection.getLatestBlockhashAndContext(); const fromPublicKey = new PublicKey(publicKey); const toPublicKey = new PublicKey(solAddr); const amount = new BN(solAmount * LAMPORTS_PER_SOL); const tx = new Transaction({ recentBlockhash: blockhash, feePayer: publicKey, }) //const blockhashInfo = await connection.getLatestBlockhash();// const tx = new Transaction({// ...blockhashInfo, feePayer: publicKey,// }); console.log("from pub key ", fromPublicKey.toString());console.log("from pub key ", publicKey.toString());console.log("to pub key ", toPublicKey.toString());console.log("system programid ", SystemProgram.programId.toString()); const transactionInstruction = new TransactionInstruction({ programId, keys: [ {pubkey: publicKey, isSigner: false, isWritable: true}, {pubkey: toPublicKey, isSigner: false, isWritable: true}, { pubkey: SystemProgram.programId, isSigner: false, isWritable: true}, // add any additional keys here ], data: encodeIxData({ discriminator: 0, amount }), }); tx.add(transactionInstruction); const simResult = await connection.simulateTransaction(tx); console.log(simResult); console.log("tx === ", tx); const signature = await sendTransaction(tx, connection, {minContextSlot}); const signatureResult = await connection.confirmTransaction({blockhash, lastValidBlockHeight, signature}); console.log(" signature ", signature); setTxnSignature(signature);}
This used via the browser with Phantom (chrome plugin). There is an error "NotEnoughKeys" -
from pub key 5EH28q5BE8GuYzUTyHuLEqzTJATxoshvJZkNWzxuLEskApp.tsx:241 from pub key 5EH28q5BE8GuYzUTyHuLEqzTJATxoshvJZkNWzxuLEskApp.tsx:242 to pub key 4dGDp3BuTaXiqJwwJhh9abUBBm6hMhRkidttr5N4CemmApp.tsx:243 system programid 11111111111111111111111111111111App.tsx:259 {context: {…}, value: {…}}context: {apiVersion: '1.14.13', slot: 198071637}value: accounts: null err: {InstructionError: Array(2)}logs: Array(3)0: "Program 7XyzLTMw7nBzoZnYoxauCzv11ruJee3HqjbxCyDfYb52 invoke [1]"1: "Program 7XyzLTMw7nBzoZnYoxauCzv11ruJee3HqjbxCyDfYb52 consumed 771 of 200000 compute units"2: "Program 7XyzLTMw7nBzoZnYoxauCzv11ruJee3HqjbxCyDfYb52 failed: insufficient account keys for instruction"
I checked the keys and the addr for the contract and they look to be OK. The Rust code for the contract -
use borsh::{BorshDeserialize, BorshSerialize};use solana_program::{ account_info::{next_account_info, AccountInfo}, entrypoint, entrypoint::ProgramResult, msg, program::invoke, pubkey::Pubkey, system_instruction,};#[derive(BorshSerialize, BorshDeserialize)]pub enum MyInstruction { Transfer { amount: u64 },}entrypoint!(process_instruction);pub fn process_instruction( _program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8],) -> ProgramResult { match MyInstruction::try_from_slice(instruction_data)? { MyInstruction::Transfer { amount } => process_transfer(accounts, amount), }}fn process_transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult { let accounts_iter = &mut accounts.iter(); let from = next_account_info(accounts_iter)?.key; let to = next_account_info(accounts_iter)?.key; msg!("Transfering {} lamports from {} to {}", amount, from, to); let transfer_ix = system_instruction::transfer(from, to, amount); invoke(&transfer_ix, accounts)}
Repo reference - https://github.com/zillerium/grizzlythonhackathon/blob/trevor/src/App.tsxDeployed contract - https://explorer.solana.com/address/7XyzLTMw7nBzoZnYoxauCzv11ruJee3HqjbxCyDfYb52?cluster=devnet
It looks like the ReactJS using the Phantom wallet cannot execute the transaction. But the txn instruction has three keys coded and they all look ok.