Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace revert strings with custom errors #4261

Merged
merged 122 commits into from
Jun 12, 2023

Conversation

ernestognw
Copy link
Member

@ernestognw ernestognw commented May 18, 2023

Fixes #2839
Fixes LIB-839

PR Checklist

Files to replace errors

  • ERC20
  • TokenTimelock
  • SafeERC20
  • ECDSA
  • ERC20Permit
  • ERC20Pausable
  • ERC20Votes
  • ERC20Wrapper
  • ERC20Snapshot
  • ERC20FlashMint
  • ERC20Capped
  • ERC4626
  • ERC777 [DEPRECATED]
  • ERC2981
  • ERC721
  • ERC721URIStorage
  • ERC721Pausable
  • ERC721Enumerable
  • ERC721Consecutive
  • ERC721Wrapper
  • ERC721Burnable
  • ERC1155
  • ERC1155Supply
  • ERC1155Pausable
  • ERC1155Burnable
  • Clones
  • Initializable
  • UUPSUpgradeable
  • ERC1967Upgrade
  • UpgradeableBeacon
  • TransparentUpgradeableProxy
  • Ownable
  • AccessControlDefaultAdminRules
  • Ownable2Step
  • AccessControl
  • ReentrancyGuard
  • Pausable
  • LibArbitrumL1 [DEPRECATED]
  • Checkpoints
  • MerkleProof
  • Counters [DEPRECATED]
  • Address
  • SafeMath [DEPRECATED]
  • Math
  • SafeCast
  • EnumerableMap
  • Create2
  • Strings
  • RefundEscrow
  • ConditionalEscrow
  • MinimalForwarder
  • GovernorCompatibilityBravo
  • Governor
  • Votes
  • GovernorTimelockCompound
  • GovernorCountingSimple
  • GovernorTimelockControl
  • GovernorSettings
  • TimelockController
  • PaymentSplitter
  • VestingWallet

Tests

  • Access
  • Finance
  • Governance
  • Meta-tx
  • Proxy
  • Security
  • Token
  • Utils

General

  • Tests
  • Documentation
  • Changeset entry (run npx changeset add)

@changeset-bot
Copy link

changeset-bot bot commented May 18, 2023

🦋 Changeset detected

Latest commit: 1cd28fe

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
openzeppelin-solidity Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ernestognw ernestognw changed the base branch from master to next-v5.0 May 18, 2023 01:25
@ernestognw ernestognw marked this pull request as draft May 18, 2023 01:25
@ernestognw ernestognw changed the title Replace revert strings with custom errors [WIP]: Replace revert strings with custom errors May 18, 2023
@socket-security
Copy link

socket-security bot commented May 18, 2023

No dependency changes detected. Learn more about Socket for GitHub ↗︎

👍 No dependency changes detected in pull request

contracts/access/IAccessControlDefaultAdminRules.sol Outdated Show resolved Hide resolved
contracts/access/Ownable2Step.sol Outdated Show resolved Hide resolved
contracts/finance/PaymentSplitter.sol Outdated Show resolved Hide resolved
contracts/finance/PaymentSplitter.sol Outdated Show resolved Hide resolved
contracts/finance/PaymentSplitter.sol Outdated Show resolved Hide resolved
contracts/finance/PaymentSplitter.sol Outdated Show resolved Hide resolved
contracts/governance/Governor.sol Outdated Show resolved Hide resolved
Copy link
Collaborator

@Amxx Amxx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left comments about the "contracts" part. Haven't touched the "tests" part yet

contracts/governance/Governor.sol Outdated Show resolved Hide resolved
contracts/governance/TimelockController.sol Outdated Show resolved Hide resolved
contracts/governance/TimelockController.sol Outdated Show resolved Hide resolved
contracts/governance/utils/IVotes.sol Outdated Show resolved Hide resolved
contracts/token/common/ERC2981.sol Outdated Show resolved Hide resolved
contracts/token/common/ERC2981.sol Outdated Show resolved Hide resolved
contracts/utils/Address.sol Outdated Show resolved Hide resolved
scripts/generate/templates/SafeCast.js Outdated Show resolved Hide resolved
ernestognw and others added 2 commits May 22, 2023 13:54
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
@Amxx
Copy link
Collaborator

Amxx commented May 23, 2023

I want to touch again on the "where errors are declared", because I fell we never took the proper time to discuss the options. We discuss the syntax of the error at length, but I think there is more to it than just how they are named. Particularly since our codebase is designed to be reused.


AFAIK, there are 4 options to declaring errors

  • In an interface
  • In a contract
  • In a library
  • Globally (file level)

I don't really like defining them globally, because it pollutes the namespace, and can cause to identifier conflicts very easily (particularly if there are many errors)

For contracts vs interfaces vs library, there is the following:

  • One cannot call an error defined in an interface that it doesn't inherit. That means that if a contract, of a library wants to use the error from an interface it needs to inherit the interface (not possible for libraries)
  • One can call an error from a contract using the revert Contract.Error() syntax. This allows library to throw errors defined in interfaces using a contract implementation as a proxy (currently done in SafeERC20 → ERC20). The downside IMO is that you are bringing a possibly big contract that the compiler will a to process, and that will appear in the verified source code even though it may not actually be used.
    • An alternative is to use an abstract contract that contains just the errors, but that is very similar to the third point (library)
  • One can call an error defined in a library using the revert Library.Error() syntax. It has similar downside to the "contract" approach, except that library tends to be smaller, with fewer dependencies, so the "bloat" is reduced.

In our codebase, we use (custom) errors in different cases:

  • In contracts that inherit a public (IMO immutable) interface such as ERC20IERC20. I think we agree on the immutability of the IERC20 interface, which is why we came up with ERC6093.
    • In that case, the current PR either creates a new interface, or add the error to existing interfaces when they are not standard.
  • In our libraries
    • In that case we either declare the errors in the library itself, or use interfaces declared elsewhere in an interface using a "proxy" implementation contract.

IMO there is real value to having clear "error" libraries, as it would improve reusing the errors in helper libraries (SafeERC20), or between contracts if/when that makes sens. All the libraries errors are already declared within the libraries, which IMO is good! Now its just a matter of moving the errors declared in contracts to dedicated libraries.

Example n°1:

I would propose that in the contracts/governance folder, next to Governor.sol and IGovernor.sol we have GovernorErrors.sol that would contain library GovernorErrors {...} and could be reused accross the code.
In particular, this file would declare all the errors for the Governor system, including the one that are used in modules but not in the core. Since 0.8.20, only the ones actually used would be part of the compiled in the ABI. So no more errors scaterred all over the modules with possible duplicates, and cleaner ABIs for the contracts.

Example n°2:

For ERC20 (and the other tokens), I would add a contracts/token/ERC20/ERC20Errors.sol that contains library ERC20Errors {...}. Note that while it doesn't match the reference implementation of ERC6093 (which we could update) it complies with the ERC, because nowhere does the ERC state that the errros must be in an interface (in the end they would be in the contract ABI just the same).
The contracts/interfaces/draft-ERC6093.sol could be built similarly to to other in this repo

pragma solidity ^0.8.0;

import "../token/ERC20/ERC20Errors.sol";
import "../token/ERC721/ERC721Errors.sol";
import "../token/ERC1155/ERC1155Errors.sol";

What do you think?

EDIT: my point includes a direct consequence, the pragma should be no lower than 0.8.20 so the custom errors get in the ABI

This was referenced Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Solidity 0.8.4 Custom Errors
5 participants