Node.js Ethereum Transfer Guide

·

Transferring ETH using Node.js is a foundational skill for developers diving into blockchain and decentralized applications. This guide walks you through setting up a simple Ethereum transaction script in a Node.js environment, leveraging essential libraries like web3.js and ethereumjs-tx. Whether you're building dApps, automating wallet operations, or exploring smart contract interactions, mastering ETH transfers is a critical first step.

We'll cover dependency installation, Web3 initialization, constructing and signing transactions, and handling common pitfalls—especially when working with testnets like Goerli. By the end, you'll have a functional script capable of sending ETH programmatically.

👉 Learn how to securely manage crypto transactions with developer tools


Installing Required Dependencies

To get started with Ethereum transactions in Node.js, you need two core packages: web3 for interacting with the Ethereum blockchain and ethereumjs-tx for signing transactions offline.

Run the following command to install them as development dependencies:

yarn add web3 ethereumjs-tx --dev

For consistency and compatibility, here are the tested versions used in this guide:

"devDependencies": {
  "web3": "^1.6.0",
  "ethereumjs-tx": "^2.1.2"
}
Note: While newer versions of ethereumjs-tx exist, this version provides stable support for legacy transaction types (before EIP-1559). If you're targeting modern networks, consider upgrading and adjusting the transaction format accordingly.

Initializing Web3 Provider

To interact with the Ethereum network without running a local node, we use a remote RPC endpoint. Infura is one of the most popular services offering free access to Ethereum testnets and mainnet.

Replace "your-infura-project-id" with your actual Infura project ID below:

const Web3 = require('web3');
const rpcUrl = "https://goerli.infura.io/v3/your-infura-project-id";
const web3Provider = new Web3.providers.HttpProvider(rpcUrl);
const web3 = new Web3(web3Provider);

This setup connects your script to the Goerli testnet, allowing you to test transactions without spending real ETH. You can switch to other networks (e.g., Sepolia or mainnet) by changing the URL accordingly.


Sending an ETH Transaction

Now that Web3 is initialized, let’s construct a transaction to send ETH from one address to another.

Key Components of the Transaction

Here’s the complete code:

const EthereumTx = require('ethereumjs-tx').Transaction;

const currentAddress = '0x3EcAa09DD6B8828607bba4B1d7055Ea1143f8B94';
const toAddress = '0xe208D2fB37df02061B78848B83F02b4AD33540e1';
const privateKey = Buffer.from('your-private-key-here', 'hex');

const start = async () => {
  // Check current balance
  const balance = await web3.eth.getBalance(currentAddress);
  console.log("Current Balance (Wei):", balance);

  // Convert 1 ETH to Wei (hex format)
  const amount = web3.utils.toHex(web3.utils.toWei('1', 'ether'));

  // Get transaction count (nonce)
  const count = await web3.eth.getTransactionCount(currentAddress);

  // Build transaction parameters
  const txParams = {
    from: currentAddress,
    to: toAddress,
    gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')), // 10 Gwei
    gasLimit: web3.utils.toHex(21000), // Standard limit for ETH transfer
    value: amount,
    nonce: web3.utils.toHex(count)
  };

  // Create and sign transaction
  const tx = new EthereumTx(txParams, { chain: 'goerli' });
  tx.sign(privateKey);

  // Broadcast signed transaction
  web3.eth.sendSignedTransaction('0x' + tx.serialize().toString('hex'))
    .on('transactionHash', hash => {
      console.log("Transaction Hash:", hash);
    })
    .catch(err => {
      console.error("Error:", err);
    });
};

start();

Upon successful execution, the script logs the transaction hash. You can verify its status on Goerli Etherscan by pasting the hash.

👉 Discover secure ways to handle private keys and blockchain interactions


Supporting Custom or Non-Standard Networks

The ethereumjs-tx library supports predefined chains like mainnet, ropsten, rinkeby, kovan, and goerli. However, if you're working with a custom network (e.g., Fantom, BSC, or Polygon), you must define chain parameters manually using ethereumjs-common.

Example for Fantom Opera network:

const Common = require('ethereumjs-common').default;

const fantomCommon = Common.forCustomChain(
  'mainnet',
  {
    name: 'Fantom Opera',
    networkId: 250,
    chainId: 250
  },
  'petersburg'
);

const tx = new EthereumTx(txParams, { common: fantomCommon });
tx.sign(privateKey);

This ensures proper signature formatting and prevents errors like invalid sender.


Core Keywords for SEO Optimization

To align with search intent and improve visibility, here are the key terms naturally integrated throughout this guide:

These keywords reflect common queries from developers seeking practical tutorials on executing Ethereum transactions via code.


Frequently Asked Questions

Can I use this method on the Ethereum mainnet?

Yes. Simply replace the Infura URL with the mainnet endpoint (https://mainnet.infura.io/v3/YOUR_PROJECT_ID) and ensure your wallet has sufficient ETH. Adjust gas settings according to current network fees.

Is it safe to use private keys in code?

No. Storing private keys in plaintext is highly insecure. For production environments, use environment variables, encrypted vaults, or hardware wallets. Never commit private keys to version control.

Why do I get "invalid sender" error?

This usually occurs when the chain specification is missing or incorrect. Always specify { chain: 'goerli' } or use Common for custom chains to match network rules.

What is nonce, and why does it matter?

Nonce represents the number of transactions sent from an address. It prevents replay attacks and ensures transaction order. Using an incorrect nonce (too low or too high) will cause rejection.

How much gas should I set for a basic transfer?

A standard ETH transfer requires 21,000 gas. Setting lower may result in failure; higher is safe but costs more. Use tools like EthGasStation to estimate optimal gas prices.

Can I upgrade this to support EIP-1559 transactions?

Yes. For networks supporting EIP-1559 (like mainnet post-London), use FeeMarketEIP1559Transaction from @ethereumjs/tx instead of legacy transactions. Update txParams to include maxPriorityFeePerGas and maxFeePerGas.


👉 Access advanced blockchain development tools and APIs

By following this guide, you now have a working foundation for sending ETH using Node.js. As you progress, consider integrating wallet abstraction layers like ethers.js or enhancing security with HD wallets and multisig patterns. Always test thoroughly on testnets before deploying to production.