Why did the ERC20Snapshots extension disappear from the wizard? Where can I find the example of its usage now?
ERC20Snapshot removed in version 5.0.0:
The following contracts, libraries, and functions were removed:
Address.isContract(because of its ambiguous nature and potential for misuse)
ERC165Storage(in favor of inheritance based approach)
GovernorProposalThreshold(deprecated since 4.4)
TokenTimelock(in favor of
- All escrow contracts (
- All cross-chain contracts, including
AccessControlCrossChainand all the vendored bridge interfaces
- All presets in favor of OpenZeppelin Contracts Wizard
It was indeed removed for 5.0, and similarly from the Wizard.
We now recommend using
However, we need the Snapshots extension for different purposes than governance, so Votes are unsuitable.
In theory, considering the previous implementation of the ERC20Snapshots extension, I can write the updated one supporting new features such as the
_update function instead of token hooks. But the problem is that the previous ERC20Snapshots used the Counters, which are now removed and are unclear how to be replaced.
How should I act in this situation? I don't really want to use older versions of contracts because I see significantly favorable changes in the new versions.
Note that you've marked this as a solution to your question, so it is likely that no one will try to answer it.
I, too, am looking for a way to know about historical balances at certain points in time. While I was not exactly overwhelmed with the snapshot feature, I am much less happy with the Votes feature, because the gas overhead seems much bigger even.
Will look into offchain solutions now. Please keep me up to date on the path you are going to take, maybe we can help each other out!
I'm not in charge of OZ path, but regarding your note about events - I usually fetch them from an Ethereum Node, i.e., using an offchain script.
Unlike fetching the value of a state-variable in an older block, which requires an Archive Node, which you will likely need to subscribe and pay for, fetching an event which was emitted in an older block can be done via any Node, which you may be able to use for free (for example, via the Infura service).
thanks for the reply and sorry I was so unclear in my wording. I wanted @jusikX to share which path he is going to take with his problem.
Fetching events is interesting, too, thanks for that hint!
I rewrote the ERC20Snapshot extension, taking into consideration the v5 release:
- Introduced custom errors
_updatefunction instead of the
- rejected the use of the
Counterslibrary in favor of simple uint256 variable
Regarding Counters: the counter turned out to be a simple uint256 value but allowed to overflow (when the counter value reaches a max value of uint256, it will simply reset to its default value, i.e., 0, instead of throwing an exception). I believe the library was deleted because of its rare use, redundant in most cases because you can add
unchecked everywhere it is needed, and gas optimization, respectively.
In our case, the fact that unit256 could overflow without reverting is a vulnerability. So, I used a simple uint256 variable instead of a counter from Counters.
When I am finished and have more time, I will try contributing to OpenZeppelin with the updated ERC20Snapshot extension.
Still, I think the current version of the Snapshot extension is far from perfect, probably that's why it was removed.
uint256 counter which starts at 0 and increments by 1 on every iteration will never overflow.
First off, because the transaction will exceed the block gas-limit and revert way ahead of time.
Second, because 2^256 is approximately the number of atoms in the visible (reachable) universe, so there is not enough mass in that part of the universe, let alone on our planet, to support the energy required for this loop to continue rolling for 2^256 iterations.
Hence, for this type of loops it is considered safe to use
Note that support for unchecked-loop-incrementing was even added on solc version 0.8.22:
- Unchecked loop increments
- Adding support for importing EVM Assembly JSON (experimental)
- Adjusting Yul optimizer to rematerialize zero literals
Oh I see this works for loops.
But what about the use of a counter for snapshotId snapshots. It is not implemented in a loop, it is incremented every time the snapshot() function is called.
It theory it shall not exceed the max value only because of
Second, because 2^256 is approximately the number of atoms in the visible (reachable) universe
Yes, in this case, the block gas-limit is not a factor, since the increment takes place only once during every transaction (which also means that whether or not the counter is
unchecked is insignificant).
But in either case, for a counter which starts at 0, it would take 2^256 transactions to overflow, and that - of course - is not a practical scenario.
I recommend checking this reply for more context about how we recommend replicating the ERC20Snapshot functionalities.
Thanks, @ernestognw. I really appreciate your help!