Search code examples
javascriptanchorsolanasolana-web3js

How to get a user's keypair from their public key only (Solana)?


I'm making a dApp and I want to add a button where a user (the one with their wallet connected) can send exactly 0.01 SOL to another user. I already wrote the function in my Rust program and after testing it with anchor test it seems to be working when I use my own personal wallet's Keypair to sign the transaction. However, now I am writing the event handler function in my web app's frontend and I'm not sure what to pass for the signers parameter if I want the user to sign the transaction. What do I pass if I don't know their secret key? Is there a way that I can generate a user's Keypair from their public key alone or would I need to use the Solana Wallet Adapter for this? Any help would be appreciated. This is my first time working with Solana!

This is the function:

const tipSol = async (receiverAddress) => {
    try {
      const provider = getProvider();
      const program = new Program(idl, programID, provider);

      const lamportsToSend = LAMPORTS_PER_SOL / 100;
      const amount = new anchor.BN(lamportsToSend);
      await program.rpc.sendSol(amount, {
      accounts: {
        from: walletAddress,
        to: receiverAddress,
        systemProgram: SystemProgram.programId,
      },
      signers: ?
     })
     console.log('Successfully sent 0.01 SOL!')
     window.alert(`You successfully tipped ${receiverAddress} 0.01 SOL!`)
    } catch (error) {
      console.error('Failed to send SOL:', error);
      window.alert('Failed to send SOL:', error);
    }
  }

Solution

  • Frontends never access private keys. Instead the flow is something like:

    • Frontend creates the transaction
    • Frontend sends the transaction to the wallet
    • Wallet signs the transaction
    • Wallet returns the signed transaction to the frontend
    • Frontend send the transaction

    You can use the @solana/wallet-adapter to implement this on your frontend https://github.com/solana-labs/wallet-adapter

    In practice it would be something like this in your frontend

    export const Component = () => {
      const { connection } = useConnection();
      const { sendTransaction } = useWallet();
    
      const handle = async () => {
        const ix: TransactionInstruction = await tipSol(receiverKey);
        const tx = new Transaction().add(ix);
        const sig = await sendTransaction(tx, connection);
      };
    
      // ...
    };