Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using local private key with Web3.js

How can I interact with smart contracts and send transactions with Web3.js by having a local private key? The private key is either hardcoded or comes from an environment (.env) file?

This is needed for Node.js and server-side interaction or batch jobs with Ethereum/Polygon/Binance Smart Chain smart contracts.

You may encounter e.g. the error

Error: The method eth_sendTransaction does not exist/is not available
like image 800
Mikko Ohtamaa Avatar asked Jul 27 '26 06:07

Mikko Ohtamaa


2 Answers

Ethereum node providers like Infura, QuikNode and others require you to sign outgoing transactions locally before you broadcast them through their node.

Web3.js does not have this function built-in. You need to use @truffle/hdwallet-provider package as a middleware for your Ethereum provider.

Example in TypeScript:


 const Web3 = require('web3');
 const HDWalletProvider = require("@truffle/hdwallet-provider");
 import { abi } from "../../build/contracts/AnythingTruffleCompiled.json";
 
 //
 // Project secrets are hardcoded here
 // - do not do this in real life
 //

 // No 0x prefix
const myPrivateKeyHex = "123123123";
const infuraProjectId = "123123123";
 
const provider = new Web3.providers.HttpProvider(`https://mainnet.infura.io/v3/${infuraProjectId}`);

// Create web3.js middleware that signs transactions locally
const localKeyProvider = new HDWalletProvider({
  privateKeys: [myPrivateKeyHex],
  providerOrUrl: provider,
});
const web3 = new Web3(localKeyProvider);

const myAccount = web3.eth.accounts.privateKeyToAccount(myPrivateKeyHex);

// Interact with existing, already deployed, smart contract on Ethereum mainnet
const address = '0x123123123123123123';
const myContract = new web3.eth.Contract(abi as any, address);

// Some example calls how to read data from the smart contract
const currentDuration = await myContract.methods.stakingTime().call();
const currentAmount = await myContract.methods.stakingAmount().call();

console.log('Transaction signer account is', myAccount.address, ', smart contract is', address);

console.log('Starting transaction now');
// Approve this balance to be used for the token swap
const receipt = await myContract.methods.myMethod(1, 2).send({ from: myAccount.address });
console.log('TX receipt', receipt);

You need to also avoid to commit your private key to any Github repository. A dotenv package is a low entry solution for secrets management.

like image 161
Mikko Ohtamaa Avatar answered Jul 30 '26 08:07

Mikko Ohtamaa


There is a better and simple way to sign and execute the smart contract function. Here your function is addBonus.

First of all we'll create the smart contract instance:

 const createInstance = () => {
  const bscProvider = new Web3(
    new Web3.providers.HttpProvider(config.get('bscRpcURL')),
  );
  const web3BSC = new Web3(bscProvider);
  const transactionContractInstance = new web3BSC.eth.Contract(
    transactionSmartContractABI,
    transactionSmartContractAddress,
  );
  return { web3BSC, transactionContractInstance };
};

Now we'll create a new function to sign and execute out addBonus Function

const updateSmartContract = async (//parameters you need) => {
     try {
    const contractInstance = createInstance();
// need to calculate gas fees for the addBonus
    const gasFees =
      await contractInstance.transactionContractInstance.methods
        .addBonus(
         // all the parameters
        )
        .estimateGas({ from: publicAddress_of_your_desired_wallet });
   const tx = {
      // this is the address responsible for this transaction
      from: chainpalsPlatformAddress,
      // target address, this could be a smart contract address
      to: transactionSmartContractAddress,
      // gas fees for the transaction
      gas: gasFees,
      // this encodes the ABI of the method and the arguments
      data: await contractInstance.transactionContractInstance.methods
        .addBonus(
       // all the parameters
        )
        .encodeABI(),
    };
  // sign the transaction with a private key. It'll return messageHash, v, r, s, rawTransaction, transactionHash
    const signPromise =
       await contractInstance.web3BSC.eth.accounts.signTransaction(
        tx,
        config.get('WALLET_PRIVATE_KEY'),
      );
    // the rawTransaction here is already serialized so you don't need to serialize it again
    // Send the signed txn
    const sendTxn =
      await contractInstance.web3BSC.eth.sendSignedTransaction(
        signPromise.rawTransaction,
      );
    return Promise.resolve(sendTxn);
} catch(error) {
  throw error;
}
    }
like image 23
Nirav Ghodadra Avatar answered Jul 30 '26 08:07

Nirav Ghodadra



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!