How to send an Ethereum transaction using Ethers JS and JavaScript

We are going to learn how to send Ethereum to another wallet from a wallet connected to your website or using the private key of a wallet using Ethers JS and JavaScript.

In this tutorial, we are going to learn how to send Ethereum to another wallet from a wallet connected to your website or using the private key of a wallet using Ethers JS and JavaScript (works with React too).

Note that this code works for all EVM networks, not just Ethereum (all the blockchains based on Ethereum like the Binance Smart Chain, Fantom, Avalanche, Polygon and all the other networks on that list: https://chainlist.org/), and will send the native token of the blockchain.

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

It all depends on your provider.

How to send Ethereum from a connected wallet using Ethers JS

To send Ethereum transactions from the user's wallet, we use the sendTransaction function:

const ethers = require('ethers');

const provider = new ethers.providers.Web3Provider(YOUR_PROVIDER_HERE);

// get a signer
const signer = provider.getSigner();

// create the transaction parameters
const tx = {
    to: "0x5b8f1310A956ee1521A7bB56160451C786289aa9",
    value: ethers.utils.parseEther("0.1"),
};

// send the transaction
signer.sendTransaction(tx)
.then((transaction) => {
    console.log("the transaction was sent: ", transaction);
    
    transaction.wait()
    .then((receipt) => {
        if (receipt && receipt.status === 1) {
            console.log("the transaction was successful!")
        }
    })
    .catch((error) => {
        console.log("the transaction failed...")
        console.log(error.receipt)
    })
});

Using the code above, we send 0.1 ETH to this address: 0x5b8f1310A956ee1521A7bB56160451C786289aa9 using the connected wallet which you can get by calling provider.getSigner().

Getting a signer to send the transaction

This returns an object of type Signer that you can use to send transactions from and in our case, it represents the user's wallet.

That Signer object has a function called sendTransaction that we can use to send any type of transactions, not just sending Ethereum.

The sendTransaction function

The sendTransaction function takes in parameter an object that contains the transaction options and returns a promise that will return a TransactionResponse object.

More about the transaction parameters and the transaction response below.

However, that promise will be fulfilled when the transaction was sent to the blockchain but not when it's completed, meaning that the transaction is still pending after you call sendTransaction even if you await for it.

How to wait for a transaction to complete

To wait for the transaction to be completed, we use the transaction.wait() function which is a promise as well and will return a transaction receipt when the transaction is completed, meaning it failed or succeeded.

The wait function takes in parameter the number of confirmations on the blockchain that you want to wait for your transaction to have. That parameter is optional and will default to 1.

When you call wait, it returns a promise. If the transaction is completed, the promise is fulfilled and returns a transaction receipt. If the transaction failed, it returns an error (that contains the transaction receipt as well).

The transaction receipt object looks pretty much like the transaction object returned by sendTransaction. We discuss errors and receipts more in details in our guide on how to handle errors when sending transactions with Ethers JS.

Passing the right value to sendTransaction

We have to use ethers.utils.parseEther to pass the correct amount of ETH because the value property expects an amount in Wei and the type of that parameter is a BigNumber (a type added by Ethers).

Wei is a sub-unit of Ethereum that has 18 decimals. It is used to handle Ethereum amounts without having to deal with floaters which introduce losses of precision.
In short, 1 ETH = 1000000000000000000 Wei.

Potential issues with MetaMask and other wallets

Note that for some wallets like MetaMask, you need to request permission to access the accounts before being able to use them and use getSigner.

For that, you'll just need to do this before calling getSigner:

await provider.send("eth_requestAccounts", []);

That should fix your issues if you're not able to send the transaction or get a signer.

The transaction parameters object

The sendTransaction function expects an object in parameters that contains information about the transaction you want to send.

  • to: string containing the address to send the transaction to or an ENS name
  • from: string containing the address to send the transaction from. Optional if you use sendTransaction from a Signer or a Wallet like we've done above.
  • nonce: (optional) a unique number that should be set to the number of transactions sent from this address. If it's the first transaction, nonce should be 1, then 2 for the second transaction and so on.
    This is important because if you fire a transaction with a nonce and while the transaction is pending, you send a new one with the same nonce, the first transaction will be canceled (only if the first transaction is still pending). If you send another transaction with a higher nonce, it will wait for all the transactions with a lower nonce to be completed. It throws an error if a completed transaction with the same nonce exists.
  • data: (optional) an hexadecimal string that contains data for the transaction. It can used when you send transactions that call a smart contract function to give information to the contract about the function you're calling and the parameters you want to pass.
  • value: (optional) the amount of Ethereum to send in Wei. The type of that parameter is BigNumber which is a type that allows you to handle large numbers like wei.
    The simplest way to set the correct value here is to use ethers.utils.parseEther() and pass the amount of Ethereum you want to send as a string like we've done in the example above.
  • gasLimit: (optional) the maximum amount of gas this transaction can use. If empty, Ethers will automatically set it by estimating the gas needed for the transaction. You need to pass a BigNumber here as well.
  • gasPrice: (optional) the price per unit of gas the transaction will use. If not set, Ethers will use the current gas price on the blockchain. The type of this property is BigNumber
  • chainId: a number that is the chain ID of the only network where the transaction is authorised. If set to 0 the transaction is authorised on any blockchain which is dangerous because the transaction can be replayed on other networks. Ethers sets the right value by default.
    To see the full list of chain IDs: https://chainlist.org/

There is also other properties but they are only used in very edge cases or legacy code so you don't need to care about it unless you're doing something that specifically needs it.

The transaction response object

This object is what the sendTransaction function returns after the transaction is sent to the blockchain (not after it's completed, it's usually still pending at this point):

  • blockNumber: The number of the block this transaction is in or null if still pending
  • blockHash: The hash of the block this transaction is in or null if still pending
  • timestamp: the timestamp of the block this transaction is in or null if still pending
  • confirmations: The number of confirmations the transaction has. In other words, the number of blocks that have been mined (including the initial block) since this transaction was mined.
  • raw: An hexadecimal string containing the transaction information
  • wait: A function that allows you to wait for the transaction to be completed. It takes in parameters the number of confirmations you want to wait for.
    It returns a promise that will be fulfilled with the transaction receipt if the transaction is successful, otherwise the promise rejects with an error.
  • type: A number that represents the EIP-2718 type of this transaction.
  • accessList: The AccessList array included in the transaction or null if the transaction type doesn't support access lists.

How to send Ethereum from a wallet using its private key with Ethers JS

If you want send Ethereum from an account of which you have the private key, you have to get a signer a bit differently.

You need to create an object of type Wallet using the private key:

const signer = new ethers.Wallet(YOUR_PRIVATE_KEY, provider);

The rest of the code to send the transaction will be the same, you can use the sendTransaction function the same way as above.

And that's it 🎉

Thank you for reading this article