6

Two USDC transfers in the same block, both between non-contract addresses. Both call the same smart contract function transfer() but used very different gas. Some differences I can explain (see below) but others I can't.

Gas usage for tx1 is 65625 and for tx2 is 43725. That's a difference of 21900.

Both transactions transfer between non-contract addresses.

GETH debug traces:

  1. Before step [1], the remaining gas (the Gas column) is GasLimit - 21605 (where I recall that the 21605 comes from the minimum 21600 plus 5 gas from somewhere else I forgot). So in the GETH debug trace tx1 starts with 66163-21605=44558 gas and tx2 starts with 73188-21605=51583. So far so good.

  2. At step [122] when executing DELEGATECALL tx1 used 39328 gas and tx2 used 46243 gas. This accounts for -6915 of the difference.

  3. At step [435] when executing SSTORE tx1 used 20000 and tx2 used 2900. This accounts for 17100 of the difference. The yellow paper says SSTORE uses 20000 gas when the storage value is set to non-zero from zero (this is the 2nd SSTORE call, and given it goes from 0 to >0 then I take it it's the destination address that is receiving funds).

The above are the only two differences in GasCost, which account for 17100-6915=10185 so they do not explain the full difference of 21900 gas. There is still 11715 gas difference that remains unexplained.

Questions:

  • Why does DELEGATECALL use different gas at step [122]?

  • Can someone explain where the rest of the gas usage difference of 11715 gas comes from?

EDIT: See the comments below from @Nulik regarding gas refund, which is the main culprit (and doesn't show in the VM opcode trace). @Nulik please post an answer so I can accept and upvote it.

11
  • the first link to etherscan is broken, tx hash invalid error shows up
    – Nulik
    Dec 22, 2022 at 18:32
  • since the cost of a CALL (delegate, static, etc) depends on current memory usage, most likely the difference is due to different memory size.
    – Nulik
    Dec 22, 2022 at 18:54
  • 2
    ahhh! maybe you spotted the gas refund effect. if the VM trace doesn't show some gas, then it must be because of gas refund for releasing storage. this is done at the end of the transaction (here: github.com/ethereum/go-ethereum/blob/… ) after transaction ends, and if it was successful, the gas is refunded at this line: github.com/ethereum/go-ethereum/blob/…
    – Nulik
    Dec 23, 2022 at 2:47
  • 2
    @Normadize have you tried a gas profiler like Tenderly one? iirc, gas refund is explicitly showed Dec 24, 2022 at 8:18
  • 2
    @DrGorilla.eth thanks for that, I didn't know that tool. It's quite neat too. Indeed it shows a gas refund of 11825 gas: dashboard.tenderly.co/tx/mainnet/… ... whereas the other tx has no gas refund. The refund is 110 gas larger than the total difference, so there is still -110 gas difference to explain (I'll dig deeper later) but the bulk is now clear.
    – Normadize
    Dec 24, 2022 at 20:09

1 Answer 1

0

One of the reason for the gas cost not being the same would be that one account did not have any usdc before the transaction and the other already had some. It cost more gas to set a 0 value to non zero than non zero to non zero.

For instance. The new account does not have his address written in the usdc balance mapping. So the contract would have to record the address and set the balance. The other account already have is address written and we just updated the balance.

See; Why does zero to non-zero in storage take higher gas?

1
  • I wonder if you read the full post, as I already identified and discussed the SSTORE difference
    – Normadize
    Dec 23, 2022 at 0:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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