Better Programming

Advice for programmers.

Follow publication

How to Listen for Speed Up and Cancelled Transactions on Ethereum?

Did you come across a challenge of confirming speed up and canceling transactions? Look no more! Here’s the solution

Simon Colby
Better Programming
Published in
7 min readMar 21, 2022
Listening for speed-ups in Metamask be like…

Recently, I was responsible for creating a system that allows for canceled and speed up transaction monitoring? You don’t know what I’m talking about? You’re a lucky man/woman (or irresponsible one). Maybe you just didn’t consider the existence of the problem. Let me tell you what I am talking about.

If you’re creating a dapp, there is a high chance that your users will interact with a blockchain and transactions through a Metamask. While the first transaction with a given nonce always happens straight from your dapp, and you’re able to know about user action, the following ones do not really. Apart from a usual transaction, you also have two options there (as you can see on the screenshot below) which are:

  1. Speed up,
  2. Cancel.
Speed up & Cancel actions on Metamask

Let’s start from the beginning.

Ideal scenario

Happy state representation

In an ideal world, where people don’t play with Metamask outside of your app you have full control over the process, i.e. you can easily verify if the transaction was successful, the UX is flawless and there’s no need for additional checks. Unfortunately, as it often is with ideal worlds, they don’t really exist.

Ethereum Transaction

In order to better understand a problem, we have to examine how do transactions in Ethereum looks underneath. Apart from data, value, from, to, gas, gasLimit, etc. they also have two important properties. Its nonce, and transaction hash. A nonce is simply a counter of transactions made from a given address, which protect from “Double spend attack“, and transaction hash is simply a hash counted from all of the other properties.

Speed up

Since everything oscillates around money, Ethereum is no different. When it comes to transactions prosecution order, miners pick the most profitable transactions i.e., the ones with the highest gas value. Let’s assume you’ve made a transaction, but it's unconfirmed for a long time. You want to speed it up so you… Exactly what are you doing here, apart from clicking a speed-up button?

You create a 2nd transaction with the same nonce, and higher gas hoping that it will be picked up by miners faster. Since the hash is calculated based on all of the parameters, it will differ from the first transaction, because the gas is different. The challenge starts here. Since you can speed up the transaction from literally every page, just by using the Metamask, there is no way to catch this information in-app, from Metamask. We have to approach it differently.

Cancel

The cancelation process is almost exactly the same as the speed-up one. If your transaction hasn’t been confirmed yet, there is a chance that you can save your transaction value (you’ll still have to pay the gas). Since ethereum will reject the transaction with the same nonce, if it already exists, you create a transaction with the same nonce that you want to cancel, you set the value to 0, and set a higher gas, hoping that miners will pick this transaction up faster then the one with the value.

Not that complicated, right? I would even say that it’s brilliant. But since there is no mechanism for fetching user actions straight for Metamask for these two activities we have to improvise. That's where the fun begins.

How we’ll gonna approach this problem

First, we have to notice similarities between these two transactions. A nonce is the same, from address is the same, and with only these two properties we’re able to uniquely distinguish the transaction coming from an address.

Comparison of tx differences

Secondly, we have to look at what we’ll need in order to be able to say that transaction was confirmed. It’s a transaction hash (txHash). That’s all! A detailed mechanism will be discussed in the following sections with code as an example.

Javascript Implementation

1. Frontend

Suggested implementation

We’ll do it like that. On the frontend, after we create a transaction we’ll just grab transaction info like txHash, nonce, from, to, etc., and POST it to our backend.

We could listen to the confirmation on the frontend but since the probability that transaction will be confirmed while a user will still be on our site (since, it’s a callback function, he is required to still be on our site, to catch the confirmation) is very low, let’s just grab the transaction info, delegate it to the backend, and let the frontend be frontend.

Sending a transaction on the frontend

2. Backend

Backend will do the heavy lifting here. Let’s start with a simple express endpoint that will be responsible for fetching txInfo.

A simple express server implementation

TxToWatch is just a JavaScript object. I’ve chosen it over the array because it’s easier to manage in that case. We need 3 things in order to be able to distinguish transactions:

  1. From address,
  2. Nonce,
  3. Transaction hashes.

Remember to lowerCase from and to, because it doesn’t matter after all, and it can be a reason why a comparison is false. After object creation, we save it in the txToWatch dictionary structuring it like below.

addTxToWatch

Beforehand we have to create a blockchain node, and since we will check a lot of requests, I suggest using Infura for that. You can use it for free, up to 100k requests per day. It’s not that much, but much enough for development purposes.

Node init

You can initialize it as above. Grab project id from Infura and create a variable with that name in a code.

That’s the easy stuff. Before I’ll show you how to create a sniffer, let’s describe what we’ll do. In order to find out about all of the transactions we can’t just listen for a confirmed transaction, because there will be only one confirmed transaction for a given nonce, and as we know from earlier, we can have multiple pending transactions with a given nonce.

Fortunately, there is an event that we can subscribe to, and which will list us all of the pending transactions, i.e. transactions which have not been confirmed yet. Bingo! After retrieving pending transactions information in order to be able to tell if a transaction was submitted or not, we have to watch for blockNumber and blockHash information. If they’re set to null it means that they haven’t been confirmed yet. If blockNumber and blockHash are present it means that the transaction was included in a block and has been confirmed.

Watching transactions mechanism

If we take my explanation from the paragraph before, it would translate to the code you can see above. For every pending transaction (by pending transaction, it’s best to just visualize it as an unconfirmed one i.e. you don’t know if it was included in the block or if it wasn’t), we trigger a subscription event, which returns us a transaction Hash, which we can use to get transaction info. Then we check for block number presence, and if we found one we set the success parameter to true in the txToWatch array.

From what I noticed, there is a chance that you’ll miss your transaction just by listening to pending transactions. Blockchain is distributed around a lot of different nodes. Since pending transactions are not reflected in actual blockchain, because they haven’t been mined yet, there is no guarantee that you’ll sniff what you’re sniffing for.

That’s why I’ve also created a txToWatch sniffer, i.e. iterate over a txToWatch transaction and check every transaction hash you have there.

TxToWatch sniffer

It looks and works similarly to watch transactions function, it just is proactive, i.e. instead of passively listening, it actively checks if transactions we watch, were reflected in a blockchain.

Checking for the transaction result

Thanks for the structuring which we’ve made earlier, it’s now possible to check for speedups, and cancelations using the firstly created hash (the one which we got back when signing with Metamask from our site).

New express endpoint, and checkTxHash function

And since we’ve organized it nicely into a dictionary, we can use conditional chaining to gracefully check if a given transaction was successful.

Happy coding!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Simon Colby
Simon Colby

Written by Simon Colby

Blockchain, crypto, full-stack. Make the world decentralised again 🌎

Responses (2)

Write a response