How to send an Ethereum transaction using Web3 and JavaScript

In this tutorial, we are going to learn how to transfer Ethereum from an address to another with the JavaScript web3 library.

In this tutorial, we are going to learn how to transfer Ethereum from an address to another with the JavaScript web3 library. Either with a private key or a connected wallet.

Note that this also works for all EVM blockchains. That means that you can use the same code to:

  • send BNB on the Binance Smart Chain network
  • send FTM on the Fantom network
  • send MATIC on the Polygon network
  • send AVAX on the Avalanche network

...etc

The only thing that will determine that is the the network of the provider you're using. If it's an HTTP provider (an API) then it's the network that the API is connected to that matters. If you're connected to a user's wallet, it's the selected wallet on that network that matters.

Here you can find a list of all EVM blockchains: https://chainlist.org/

First, install the web3 library:

npm install web3

and import it:

import Web3 from 'web3';

Now, you need to instantiate Web3 with a provider. It can be an HTTP provider (like Infura or another node provider API) or it can be a wallet that the user connected to your website.

Learn how to connect a wallet to your website here

In this tutorial, we use Infura as it supports Ethereum:

const web3 = new Web3(new Web3.providers.HttpProvider("INFURA_URL_HERE"));

Then you have 2 options, either a wallet is connected to your website and you can send a transaction with it after the user's confirmation or you have the private key of the account you send the transaction from as a string.

Send an Ethereum transaction from a connected wallet

To send a transaction from a connected wallet, all you have to do, assuming you already have a Web3 instance, is use the sendTransaction method:

const amount = "1.5"

web3.eth.sendTransaction({
    from: fromAddress,
    to: toAddress,
    value: Web3.utils.toHex(Web3.utils.toWei(amount, 'ether')),
})
.on('transactionHash', () => {
    // Do something when transaction reached the blockchain and you get the transaction hash
})
.on('error', () => {
    // Do something if an error happens
});
  • fromAddress is the address of the account of the connected wallet. To get that, you can use this code:
const accounts = await web3.eth.getAccounts();
const fromAddress = accounts[0]
  • toAddress is a string containing the address that you want to send the transaction to
  • amount being a String containing the amount that you want to send. In the example above, we set it to "1.5" which means we will send 1.5 ETH. The util function above converts it to Wei which is a smaller unit used for transaction for better precision.

Note that this function returns a Promise containing the receipt of the transaction (all the transaction information) when the transaction passed successfully or failed.

That means you can do:

const receipt = await web3.eth.sendTransaction({
    from: fromAddress,
    to: toAddress,
    value: Web3.utils.toHex(Web3.utils.toWei(amount, 'ether')),
})

// EQUIVALENT:

web3.eth.sendTransaction({
    from: fromAddress,
    to: toAddress,
    value: Web3.utils.toHex(Web3.utils.toWei(amount, 'ether')),
})
.then(receipt => {
    // Do something when transaction completes
})

If you want to wait for the transaction to complete.

Send an Ethereum transaction with the account's private key as a String

It's a bit more complicated than the other method. To send a transaction from an account using it's private key, you have to:

  • Create a transaction object
  • Sign the transaction with the private key
  • Send the signed transaction

Here is the code to do that:

const amount = "1.5"
const pk = "PRIVATE_KEY_HERE"

const params = {
    to: toAddress,
    value: Web3.utils.toHex(Web3.utils.toWei(amount, 'ether')),
    gas: Web3.utils.toHex(21000), // optional
    gasPrice: Web3.utils.toHex(20 * Math.pow(10, 9)), // optional
};

const signedTx = await web3.eth.accounts.signTransaction(params, pk);

web3.eth.sendSignedTransaction(signedTx.rawTransaction)
.on('transactionHash', () => {
    // Do something when transaction reached the blockchain and you get the transaction hash
})
.on('error', () => {
    // Do something if an error happens
});
  • pk is the private key of the account you want to send the transaction from
  • toAddress is the address you want to send the transaction to
  • amount is the amount you want to send, as a String. In the example above we set it to "1.5" so we are going to send 1.5 ETH
  • gas in the transaction parameters is the gas amount to use, it will always be 21000 for Ethereum transactions
  • gasPrice in the transaction parameters is the maximum gas price you want your transaction to use. Here we set it to 20 Gwei to demonstrate that if you set it to a high value, the transaction is more likely to pass and it will pass faster. However, it won't use all the gas you set, it will only use the gas that's necessary. By default, it is set to the current gas price that is returned by web3.eth.gasPrice.
  • Both gas and gasPrice are optional but you can use it to control your transaction fees and make sure transactions pass. Like it is said above, unused gas is refunded.

Note that this function returns a Promise containing the receipt of the transaction (all the transaction information) when the transaction passed successfully or failed. Just like the other one above.

That means you can await for it or use .then to wait for it to complete and act after that.

And that's it! 👏

Thanks for reading this article!