Skip to content

Commit ce00023

Browse files
committed
Merge branch 'master' into EIP712-getters
2 parents 37102d5 + fe08f58 commit ce00023

File tree

140 files changed

+3225
-1290
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+3225
-1290
lines changed

.changeset/lovely-geckos-hide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': major
3+
---
4+
5+
Replace revert strings and require statements with custom errors.

GUIDELINES.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,17 @@ In addition to the official Solidity Style Guide we have a number of other conve
115115
```
116116

117117
* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted.
118+
119+
* Custom errors should be declared following the [EIP-6093](https://eips.ethereum.org/EIPS/eip-6093) rationale whenever reasonable. Also, consider the following:
120+
121+
* The domain prefix should be picked in the following order:
122+
1. Use `ERC<number>` if the error is a violation of an ERC specification.
123+
2. Use the name of the underlying component where it belongs (eg. `Governor`, `ECDSA`, or `Timelock`).
124+
125+
* The location of custom errors should be decided in the following order:
126+
1. Take the errors from their underlying ERCs if they're already defined.
127+
2. Declare the errors in the underlying interface/library if the error makes sense in its context.
128+
3. Declare the error in the implementation if the underlying interface/library is not suitable to do so (eg. interface/library already specified in an ERC).
129+
4. Declare the error in an extension if the error only happens in such extension or child contracts.
130+
131+
* Custom error names should not be declared twice along the library to avoid duplicated identifier declarations when inheriting from multiple contracts.

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ Finally, you may want to take a look at the [guides on our blog](https://blog.op
7070

7171
This project is maintained by [OpenZeppelin](https://openzeppelin.com) with the goal of providing a secure and reliable library of smart contract components for the ecosystem. We address security through risk management in various areas such as engineering and open source best practices, scoping and API design, multi-layered review processes, and incident response preparedness.
7272

73-
The security policy is detailed in [`SECURITY.md`](./SECURITY.md), and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities.
73+
The [OpenZeppelin Contracts Security Center](https://contracts.openzeppelin.com/security) contains more details about the secure development process.
74+
75+
The security policy is detailed in [`SECURITY.md`](./SECURITY.md) as well, and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities.
7476

7577
The engineering guidelines we follow to promote project quality can be found in [`GUIDELINES.md`](./GUIDELINES.md).
7678

contracts/access/AccessControl.sol

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
107107
*/
108108
function _checkRole(bytes32 role, address account) internal view virtual {
109109
if (!hasRole(role, account)) {
110-
revert(
111-
string(
112-
abi.encodePacked(
113-
"AccessControl: account ",
114-
Strings.toHexString(account),
115-
" is missing role ",
116-
Strings.toHexString(uint256(role), 32)
117-
)
118-
)
119-
);
110+
revert AccessControlUnauthorizedAccount(account, role);
120111
}
121112
}
122113

@@ -173,14 +164,16 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
173164
*
174165
* Requirements:
175166
*
176-
* - the caller must be `account`.
167+
* - the caller must be `callerConfirmation`.
177168
*
178169
* May emit a {RoleRevoked} event.
179170
*/
180-
function renounceRole(bytes32 role, address account) public virtual {
181-
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
171+
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
172+
if (callerConfirmation != _msgSender()) {
173+
revert AccessControlBadConfirmation();
174+
}
182175

183-
_revokeRole(role, account);
176+
_revokeRole(role, callerConfirmation);
184177
}
185178

186179
/**

contracts/access/AccessControlDefaultAdminRules.sol

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
5353
* @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
5454
*/
5555
constructor(uint48 initialDelay, address initialDefaultAdmin) {
56-
require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin");
56+
if (initialDefaultAdmin == address(0)) {
57+
revert AccessControlInvalidDefaultAdmin(address(0));
58+
}
5759
_currentDelay = initialDelay;
5860
_grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
5961
}
@@ -80,15 +82,19 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
8082
* @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
8183
*/
8284
function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
83-
require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly grant default admin role");
85+
if (role == DEFAULT_ADMIN_ROLE) {
86+
revert AccessControlEnforcedDefaultAdminRules();
87+
}
8488
super.grantRole(role, account);
8589
}
8690

8791
/**
8892
* @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
8993
*/
9094
function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
91-
require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly revoke default admin role");
95+
if (role == DEFAULT_ADMIN_ROLE) {
96+
revert AccessControlEnforcedDefaultAdminRules();
97+
}
9298
super.revokeRole(role, account);
9399
}
94100

@@ -108,10 +114,9 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
108114
function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
109115
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
110116
(address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
111-
require(
112-
newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule),
113-
"AccessControl: only can renounce in two delayed steps"
114-
);
117+
if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
118+
revert AccessControlEnforcedDefaultAdminDelay(schedule);
119+
}
115120
delete _pendingDefaultAdminSchedule;
116121
}
117122
super.renounceRole(role, account);
@@ -128,7 +133,9 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
128133
*/
129134
function _grantRole(bytes32 role, address account) internal virtual override {
130135
if (role == DEFAULT_ADMIN_ROLE) {
131-
require(defaultAdmin() == address(0), "AccessControl: default admin already granted");
136+
if (defaultAdmin() != address(0)) {
137+
revert AccessControlEnforcedDefaultAdminRules();
138+
}
132139
_currentDefaultAdmin = account;
133140
}
134141
super._grantRole(role, account);
@@ -148,7 +155,9 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
148155
* @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
149156
*/
150157
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
151-
require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules");
158+
if (role == DEFAULT_ADMIN_ROLE) {
159+
revert AccessControlEnforcedDefaultAdminRules();
160+
}
152161
super._setRoleAdmin(role, adminRole);
153162
}
154163

@@ -236,7 +245,10 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
236245
*/
237246
function acceptDefaultAdminTransfer() public virtual {
238247
(address newDefaultAdmin, ) = pendingDefaultAdmin();
239-
require(_msgSender() == newDefaultAdmin, "AccessControl: pending admin must accept");
248+
if (_msgSender() != newDefaultAdmin) {
249+
// Enforce newDefaultAdmin explicit acceptance.
250+
revert AccessControlInvalidDefaultAdmin(_msgSender());
251+
}
240252
_acceptDefaultAdminTransfer();
241253
}
242254

@@ -247,7 +259,9 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu
247259
*/
248260
function _acceptDefaultAdminTransfer() internal virtual {
249261
(address newAdmin, uint48 schedule) = pendingDefaultAdmin();
250-
require(_isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: transfer delay not passed");
262+
if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
263+
revert AccessControlEnforcedDefaultAdminDelay(schedule);
264+
}
251265
_revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
252266
_grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
253267
delete _pendingDefaultAdmin;

contracts/access/IAccessControl.sol

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ pragma solidity ^0.8.19;
77
* @dev External interface of AccessControl declared to support ERC165 detection.
88
*/
99
interface IAccessControl {
10+
/**
11+
* @dev The `account` is missing a role.
12+
*/
13+
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
14+
15+
/**
16+
* @dev The caller of a function is not the expected one.
17+
*
18+
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
19+
*/
20+
error AccessControlBadConfirmation();
21+
1022
/**
1123
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
1224
*
@@ -82,7 +94,7 @@ interface IAccessControl {
8294
*
8395
* Requirements:
8496
*
85-
* - the caller must be `account`.
97+
* - the caller must be `callerConfirmation`.
8698
*/
87-
function renounceRole(bytes32 role, address account) external;
99+
function renounceRole(bytes32 role, address callerConfirmation) external;
88100
}

contracts/access/IAccessControlDefaultAdminRules.sol

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ import "./IAccessControl.sol";
1111
* _Available since v4.9._
1212
*/
1313
interface IAccessControlDefaultAdminRules is IAccessControl {
14+
/**
15+
* @dev The new default admin is not a valid default admin.
16+
*/
17+
error AccessControlInvalidDefaultAdmin(address defaultAdmin);
18+
19+
/**
20+
* @dev At least one of the following rules was violated:
21+
*
22+
* - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.
23+
* - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.
24+
* - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.
25+
*/
26+
error AccessControlEnforcedDefaultAdminRules();
27+
28+
/**
29+
* @dev The delay for transferring the default admin delay is enforced and
30+
* the operation must wait until `schedule`.
31+
*
32+
* NOTE: `schedule` can be 0 indicating there's no transfer scheduled.
33+
*/
34+
error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);
35+
1436
/**
1537
* @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next
1638
* address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`

contracts/access/Ownable.sol

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ import "../utils/Context.sol";
2020
abstract contract Ownable is Context {
2121
address private _owner;
2222

23+
/**
24+
* @dev The caller account is not authorized to perform an operation.
25+
*/
26+
error OwnableUnauthorizedAccount(address account);
27+
28+
/**
29+
* @dev The owner is not a valid owner account. (eg. `address(0)`)
30+
*/
31+
error OwnableInvalidOwner(address owner);
32+
2333
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
2434

2535
/**
@@ -48,7 +58,9 @@ abstract contract Ownable is Context {
4858
* @dev Throws if the sender is not the owner.
4959
*/
5060
function _checkOwner() internal view virtual {
51-
require(owner() == _msgSender(), "Ownable: caller is not the owner");
61+
if (owner() != _msgSender()) {
62+
revert OwnableUnauthorizedAccount(_msgSender());
63+
}
5264
}
5365

5466
/**
@@ -67,7 +79,9 @@ abstract contract Ownable is Context {
6779
* Can only be called by the current owner.
6880
*/
6981
function transferOwnership(address newOwner) public virtual onlyOwner {
70-
require(newOwner != address(0), "Ownable: new owner is the zero address");
82+
if (newOwner == address(0)) {
83+
revert OwnableInvalidOwner(address(0));
84+
}
7185
_transferOwnership(newOwner);
7286
}
7387

contracts/access/Ownable2Step.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ abstract contract Ownable2Step is Ownable {
5151
*/
5252
function acceptOwnership() public virtual {
5353
address sender = _msgSender();
54-
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
54+
if (pendingOwner() != sender) {
55+
revert OwnableUnauthorizedAccount(sender);
56+
}
5557
_transferOwnership(sender);
5658
}
5759
}

contracts/finance/VestingWallet.sol

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ contract VestingWallet is Context {
2323
event EtherReleased(uint256 amount);
2424
event ERC20Released(address indexed token, uint256 amount);
2525

26+
/**
27+
* @dev The `beneficiary` is not a valid account.
28+
*/
29+
error VestingWalletInvalidBeneficiary(address beneficiary);
30+
2631
uint256 private _released;
2732
mapping(address => uint256) private _erc20Released;
2833
address private immutable _beneficiary;
@@ -33,7 +38,9 @@ contract VestingWallet is Context {
3338
* @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet.
3439
*/
3540
constructor(address beneficiaryAddress, uint64 startTimestamp, uint64 durationSeconds) payable {
36-
require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
41+
if (beneficiaryAddress == address(0)) {
42+
revert VestingWalletInvalidBeneficiary(address(0));
43+
}
3744
_beneficiary = beneficiaryAddress;
3845
_start = startTimestamp;
3946
_duration = durationSeconds;

0 commit comments

Comments
 (0)