Part 1: Decoding Ethereum dApp Development: Nonce, Gas, and Fees Explained

Simplifying key concepts in EVM blockchain development: Nonce, Gas, Gas Limit, Gas Price, maxFeePerGas, maxPriorityFeePerGas.

Β·

5 min read

You are finally there. Building your first dApp. Ethereum is the platform of your choice, so you have done your research already and performed some transactions. But, sometimes, there were some issues with broadcasting your transaction to the node. It got stuck or, even worse, didn't appear in the blockchain at all. You don't know why; you have done everything correctly.

I know how you feel. I have been there. There are a lot of things that could go wrong, and I will try to explain each one of them step by step so you will never make the same mistake again. So, get ready. πŸš€πŸš€πŸš€

πŸ’‘
EVM blockchain is a family of blockchains which uses the same principles as Ethereum. EVM is an abbreviation for Ethereum Virtual Machine, the core component of the Ethereum blockchain protocol. There are a lot of blockchains that share the same basics as Ethereum. The most known examples are Polygon, Binance Chain, or L2 protocols like Optimism or Arbitrum.

I will cover some of the key concepts of working with transactions on EVM blockchains.

  1. nonce

  2. gas consumed by transaction

  3. gasLimit set to transaction

  4. gasPrice of the gas unit

  5. maxFeePerGas and maxPriorityFeePerGas of the gas unit - new EIP-1559 standard

Nonce

One of the biggest problems, or unknowns, in the EVM world. Everyone is struggling with nonce management because this is the key component when you want to scale your transaction throughput. But let's start with the explanation.

πŸ’‘
Nonce is a pseudonym for a number used only once. In terms of the transaction, it represents a unique counter of transactions initiated by 1 blockchain address. Each address has a unique nonce counter, which is strictly sequential and starts from 0.

When you are preparing your transaction, you must specify the nonce. Some blockchain SDKs specify the nonce automatically by reading it from the blockchain node.

πŸ’‘
If you want to find out the latest nonce you should provide to your transaction, you should call node RPC method eth_getTransactionCount. The method accepts 2 parameters - the wallet address you want to get the nonce and block state to consider when retrieving the transaction count. To get the most up-to-date information, including mempool, the pending keyword should be used.

But this is where problems arise.

Transaction was sent but is not visible in the explorer

One of the common problems you might face is the non-visibility of the transaction. Everything seems perfect - the transaction was prepared, signed, and broadcasted correctly, but it doesn't appear in the block. Never. Blockchain explorers can't see it. This happens when you use the wrong nonce. The nonce must be used in order, the latest successfully used nonce +1, starting from 0. Anything else will be buried inside the mempool of the blockchain node you have used for broadcasting the transaction and dropped after some time. By that time, you have very limited ways to fix this. Usually, you must send a transaction with the proper nonce and a higher fee than the false one.

πŸ’‘
The time when a transaction will be dropped by the mempool depends on the node configuration. It could be 5 minutes or hours.

Transaction was sent, but it's stuck in the explorer

Your transaction is visible in the Explorer, but the fee you have provided is so low that it can't be included in the block. Your transaction is basically stuck and pending. You have two options how to manage this:

  1. Wait for a lower fee so your transaction will be unblocked

  2. Resend the same transaction with the same nonce but a higher fee

I will cover this topic in more depth in the following posts.

Sending huge amounts of transactions in a short period of time

Your dApp is exploding, and you need to send a huge amount of transactions from the same address in a short period of time. There are multiple scenarios that could happen:

  1. You are using a blockchain RPC provider, where you can access a pool of nodes hidden behind the load balancer. Whenever you want to perform a transaction, you read the latest nonce from the node. The problem is that your request might hit different nodes, and those nodes are not synced with each other fast enough, so you can get different nonce from different nodes. This will result in your transaction being stuck in one of the mempool of the nodes because one mempool sees a different nonce based on its state than the one you used to create your transaction.

  2. You are using a dedicated RPC node. You always get the correct nonce every time you ask for it, and your transactions are being accepted by the node. But, for some reason, one of the transactions is stuck with a lower fee in the mempool. All other transactions sent after that stuck one are being stuck in the mempool as well because their order must be guaranteed. You can again replace the original one with the higher fee and speed it up.

  3. You are maintaining your own nonce counter in your application. You are 100% dependent on your app logic, and you must double-check if every transaction you have broadcasted actually hits the node and is included in the block.

Summary

There is no easy way out of the nonce issues. The most important thing is that you actually understand the problem, and you are aware of what might happen and what are the corner cases. I personally prefer approach number 2, where you are hitting a dedicated node with all the read nonce requests and transaction broadcasts. It will guarantee you the same answers. You are not relying on syncing of mempools between multiple nodes. The worst scenario is that some of your transactions might be stuck if you don't do your fee management right. That's something I will cover in the next post. Stay tuned.

Β