Search code examples
ethereumweb3jsbinance-smart-chain

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

Solution

  • 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.