How big is the ERC20 Snapshot gas cost overhead?


we are looking into the ERC20Snapshot feature to provide ... snapshots of account balances. While the documentation state that the gas "overhead is only significant for the first transfer that immediately follows a snapshot", I find that the snapshot extension increases the cost of a token transfer from ~50k to ~60k gas.

Is my observation correct? I find a 20% increase in tx cost significant, and I wonder if I am doing something wrong or if the author of the documentation has a different take on what they consider significant.

Here are some details about the project, my measurements and code analysis, and the PR they are based on.
Any help in understanding this is appreciated!

For the record, here is the aforementioned function:

    function _snapshot() internal virtual returns (uint256) {

        uint256 currentId = _currentSnapshotId.current();
        emit Snapshot(currentId);
        return currentId;

Where the snapshot id in storage is declared as Counters.Counter private _currentSnapshotId;.

I've declared it as uint256 for simplicity, and then measured the gas cost:

  • When incremented from zero to non-zero (i.e., from 0 to 1), the cost is 23366 gas
  • When incremented from non-zero to non-zero (e.g., from 1 to 2), the cost is 6266 gas

The difference is 17100 gas, which makes sense, because the cost of updating a storage-slot is:

  • 22100 gas, when updating the slot from zero to non-zero
  • 5000 gas, when updating the slot from non-zero to non-zero

The rest of the gas (1266 in both cases) goes for:

  • Reading the slot - _currentSnapshotId.current()
  • Emitting an event - emit Snapshot(currentId)

Whether or not a cost of 6266 gas is a lot relatively to the entire cost of the transfer function - I'll leave that for you to decide...

1 Like

Thank you for taking the time to look into this, @barakman!

I think you analyzed the gas usage of creating a new snapshot. As this will be a very rare event in our use case, the gas usage of ERC20Snapshot-specific _beforeTokenTransfer()-function is much more important to us.
Can you confirm that this function consumes somewhere between 7k and 10k gas in the case that no new snapshot has been created since the last transfer for both to and from?

Ah yeah, my bad. I've compared between the cost of creating a new snapshot for the very first time (~23K gas), and the cost of creating a new snapshot again (~6K gas).

So if creating a new snapshot is a rare event in general, then neither one of these two measurements is relevant to the (hypothetical) problem addressed in the question.

1 Like