8

Caveat: I tried to provide links to my transactions and addresses in etherscan.io, but I "need at least 10 reputation to post more than 2 links."

I have an account that I want to sweep. I want to sweep the ETH to a funds splitting contract (ETC/ETH). I'm only interested in sweeping the ETH balance and my goal is for the account to end up with a balance of zero (e.g. no dust).

This is the fund splitting contract I'm trying to use: 0x1e143b2588705dfea63a17f2032ca123df995ce0

It seems as if the gas required for this operation is 29,717. For example, here is a sample transaction I sent to the contract, which according to etherscan.io required that amount of gas: 0x7cd52325c0945d0de975a6713abdc50659c0c62ef523a1a99f2ad2a2d4128a8f

However, if I send a transaction and limit the amount of gas to 29,717, my transaction fails. For example, here is a sample transaction I sent to the contract with a gas limit of 29,717, which failed due to lack of gas: 0xcd31481b4dd9410daa22c8a47f9a4b29ef4a305877174eb346433bb4e6b03089 (TX)

I discovered the minimum amount of gas that I need to specify for one of these transfers to work is 31,991:

  • Transaction with 31,991 gas which worked: 0x7cd52325c0945d0de975a6713abdc50659c0c62ef523a1a99f2ad2a2d4128a8f (TX)
  • Transaction with 31,990 gas which failed: 0x8c92fde3cf07b3cdbf4dcc54ed6ccfb072f22933ab556612f3d23317a2466280 (TX)

However, when the tx goes through, it seems as if it only used 29,717 gas. For example: Account 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b (address) had a balance of 0.01282711 ETH (at block 1964300).

I sent transaction 0xb57c8b5aede3070e2fb80ea9a21ec43293cb5c7392ccb36357388422e9055509 (TX) with the following details:

  • Value: 0.01218729 ETH
  • Gas: 31991
  • Gas Price: 20000000000 Wei

So:

  • Balance before TX: 0.01282711 ETH
  • Amount to send: 0.01218729 ETH
  • Supposed cost of TX: Gas * Price = 0.00063982 ETH
  • Balance - Amount to send - Supposed cost of TX = ZERO!

However, as you can see, account 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b (address) has a balance of 0.00004548 ETH.

This in turn means that the actual cost of the TX was 0.00059434 ETH: Actual Cost of TX = Balance before TX - Amount sent - Actual End Balance = 0.01282711 - 0.01218729 - 0.00004548 = 0.00059434.

At a gas price of 20000000000 Wei, this means the amount of gas used was: 29717 (0.00059434/0.00000002 = 29717)

So the question are:

  1. Why are the transactions which specify a gas limit of 29717 failing?
  2. How do I sweep the funds so the ending balance of an ETH account is zero when using the contract above?

System information

Geth version: 1.4.10-stable-c2eea630 OS & Version: Linux

Expected behaviour

Transaction 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b should've been successful.

Actual behaviour

Transaction 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b failed due to lack of gas.

Steps to reproduce the behaviour

Use the transfer(address) function of contract 0x1e143b2588705dfea63a17f2032ca123df995ce0 by sending some amount and limit the amount of gas to 29717

Here is a sample transaction to this contract you can send via the JSON-RPC API: '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0xe7c7d161800ebb5112d7d892510e9f1dafc4010c","to":"0x1e143b2588705dfea63a17f2032ca123df995ce0","value":"0x1F99A58657EED0","data":"0x1a69523000000000000000000000000029d5527caa78f1946a409fa6acaf14a0a4a0274b"}],"id":6}'

6

Understanding this puzzle can be instructive. The behavior can be explained by the way the CALL instruction works in terms of gas.

We can compare the transactions VM traces here:

(Links are to program counter just before the failing CALL).

Let's consider both transactions in parallel, A will be the successful transaction and B the failed one. The value is the remaining gas at any step.

  1. Contract call: A = 31991, B = 29717.
  2. Before the contract even start, 22680 are consumed. A = 9311, B = 7037.
  3. A number of instructions are performed that have a cumulative cost of 271.
  4. Before the actual transfer CALL, at step 65, we are thus at A = 9040, B = 6766.
  5. At that point B fails because it doesn't have enough gas to perform the CALL instruction, which cost 9040 gas.
  6. After the call though, the 9040 gas haven't been entirely consumed in A: we are back at 2300.
  7. A continues its operations until the last instruction where it sits at 2274.
  8. The unused 2274 are refunded and the total gas consumed is indeed 31991-2274 = 29717.

There are two points that explain the surprising behavior.

  • The cost of a value-transferring CALL is 40 + 9000. (per Yellow Paper appendix G).
  • An amount of 2300 gas is taken from this cost and forwarded to the recipient as gas.

The second point is the key. In the context of a contract calling another contract, this so-called stipend is provided as minimal gas to cover operational costs of a basic fallback function. Note that it is also possible to manually forward more gas if it is known that the recipient has larger needs.

In our case, since the recipient account is not a contract, the stipend was refunded. In a sense the CALL operation cost was only 6740 gas but we had to show that we had at least 9040 to cover the case of a contract callee.

In previous versions the entire gas of the caller was forwarded to the callee, but this was open to abuse and the new behavior was put into place.

More linkies:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.