One of the neat things about running a service based on open source software is that sometimes your customers will write your features for you, as is the case with Rivet’s latest addition.

MyEtherWallet had a problem. Sometimes doing something on Ethereum requires multiple consecutive transactions that rely on in-order execution. For example, if you want to make a trade on 0x, you must first set an allowance for the 0x Exchange contract to take your tokens, then you can execute the trade itself. From a user experience perspective, the best way to do this is to present the user with two transactions to sign, send them off to the blockchain and wait for them to be mined. The problem with this approach is estimating how much gas the second transaction will use.

When you submit a transaction to the blockchain, you have to specify a gas limit for the transaction. Applications normally get the amount of gas a transaction will require by running eth_estimateGas, which runs the transaction against the current block and tells you how much gas that transaction would use right now.

But using our example from earlier, if your allowance transaction hasn’t confirmed on the blockchain, your trade transaction will fail — using drastically less gas than it would if it succeeded. If you run eth_estimateGas twice before submitting either transaction, the second transaction’s gas will be too low, and the transaction will run out of gas.

Until now, Ethereum nodes didn’t offer a good way to estimate gas for that second transaction.The workaround to date has been to use excessively high gas limits on those transactions — the extra gas gets refunded to the user, but it looks scary up front when they see how much the transaction might cost.

Introducing ethercattle_estimateGasList

Wanting to give their users the best possible experience, MyEtherWallet made a pull request to the Geth team to add an eth_estimateGasList RPC method, which allows applications to specify a list of transactions that will be executed consecutively, and the gas for each will be returned. Using our earlier example of a 0x trade, an application could submit an allowance setting transaction and a trade execution transaction together. eth_estimateGasList will execute them in order, so the gas returned for the trade execution transaction reflects the fact that the allowance was already set.

Now, the Geth team hasn’t merged this change into core Geth yet, but it has been merged into the EtherCattle fork of Geth (with a slight modification), and as of this week is available on Rivet.cloud.

When we pulled the change into EtherCattle, we renamed the RPC method ethercattle_estimateGasList. Since this is an outstanding pull-request to Geth, it’s possible it might be merged with a modified interface at some point in the future, and we don’t want to be in a situation where our version of eth_estimateGasList is different from the Core Geth version. If and when the feature gets merged into core Geth we will deprecate our version, but we want to allow for a grace period where customers who rely on this feature now can transition to a standard version.

Example

In this example, we run an ethercattle_estimateGasList query with 3 transactions, and it responds with 3 gas estimations.

curl https://ethercattlereplica/ --data '{"jsonrpc":"2.0","id":1,"method":"ethercattle_estimateGasList","params":[[{"from":"0x17b5065693f44e999d8eb692e41385e67859f838","data":"0x552410770000000000000000000000000000000000000000000000000000000000000000","to":"0x99d0e6b5bfec73c8fd96b1c067617e1287a593cc"},{"from":"0x17b5065693f44e999d8eb692e41385e67859f838","data":"0x552410770000000000000000000000000000000000000000000000000000000000000001","to":"0x99d0e6b5bfec73c8fd96b1c067617e1287a593cc"},{"from":"0x17b5065693f44e999d8eb692e41385e67859f838","data":"0x552410770000000000000000000000000000000000000000000000000000000000000002","to":"0x99d0e6b5bfec73c8fd96b1c067617e1287a593cc"}]]}'

{"jsonrpc":"2.0","id":1,"result":["0x52c8","0x52d4","0x52d4"]}

Caveats

As is always the case with gas estimation, some transactions may depend on changes to the blockchain that are beyond your control. For example, executing a trade with 0x depends not only on allowances being set, but the order having not been filled. If someone partially fills the order while your transaction sits in the mempool, the actual gas requirements could change from the estimation. For transactions that depend on state that other people can change, it’s still generally a good idea to leave some buffer on top of the estimated gas, but estimateGasList gets you a much better starting point (and any extra gas will still be refunded at the end of the transaction).