Skip to content

Commit c3e46d1

Browse files
committed
Merge branch 'master' into fix/eip712-for-delegatecalls
2 parents 141f245 + 1b27c13 commit c3e46d1

17 files changed

+20026
-62
lines changed

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
22

3-
## 4.3.1
3+
## Unreleased
4+
5+
* `Ownable`: add an internal `_transferOwnership(address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#2568))
6+
* `AccessControl`: add internal `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#2568))
7+
* `AccessControl`: mark `_setupRole(bytes32,address)` as deprecated in favor of `_grantRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#2568))
8+
9+
## 4.3.2 (2021-09-14)
10+
11+
* `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular.
12+
13+
## 4.3.1 (2021-08-26)
414

515
* `TimelockController`: Add additional isOperationReady check.
616

contracts/access/AccessControl.sol

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
150150
* purpose is to provide a mechanism for accounts to lose their privileges
151151
* if they are compromised (such as when a trusted device is misplaced).
152152
*
153-
* If the calling account had been granted `role`, emits a {RoleRevoked}
153+
* If the calling account had been revoked `role`, emits a {RoleRevoked}
154154
* event.
155155
*
156156
* Requirements:
@@ -178,6 +178,8 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
178178
* Using this function in any other way is effectively circumventing the admin
179179
* system imposed by {AccessControl}.
180180
* ====
181+
*
182+
* NOTE: This function is deprecated in favor of {_grantRole}.
181183
*/
182184
function _setupRole(bytes32 role, address account) internal virtual {
183185
_grantRole(role, account);
@@ -194,14 +196,24 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 {
194196
emit RoleAdminChanged(role, previousAdminRole, adminRole);
195197
}
196198

197-
function _grantRole(bytes32 role, address account) private {
199+
/**
200+
* @dev Grants `role` to `account`.
201+
*
202+
* Internal function without access restriction.
203+
*/
204+
function _grantRole(bytes32 role, address account) internal virtual {
198205
if (!hasRole(role, account)) {
199206
_roles[role].members[account] = true;
200207
emit RoleGranted(role, account, _msgSender());
201208
}
202209
}
203210

204-
function _revokeRole(bytes32 role, address account) private {
211+
/**
212+
* @dev Revokes `role` from `account`.
213+
*
214+
* Internal function without access restriction.
215+
*/
216+
function _revokeRole(bytes32 role, address account) internal virtual {
205217
if (hasRole(role, account)) {
206218
_roles[role].members[account] = false;
207219
emit RoleRevoked(role, account, _msgSender());

contracts/access/Ownable.sol

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ abstract contract Ownable is Context {
2525
* @dev Initializes the contract setting the deployer as the initial owner.
2626
*/
2727
constructor() {
28-
_setOwner(_msgSender());
28+
_transferOwnership(_msgSender());
2929
}
3030

3131
/**
@@ -51,7 +51,7 @@ abstract contract Ownable is Context {
5151
* thereby removing any functionality that is only available to the owner.
5252
*/
5353
function renounceOwnership() public virtual onlyOwner {
54-
_setOwner(address(0));
54+
_transferOwnership(address(0));
5555
}
5656

5757
/**
@@ -60,10 +60,14 @@ abstract contract Ownable is Context {
6060
*/
6161
function transferOwnership(address newOwner) public virtual onlyOwner {
6262
require(newOwner != address(0), "Ownable: new owner is the zero address");
63-
_setOwner(newOwner);
63+
_transferOwnership(newOwner);
6464
}
6565

66-
function _setOwner(address newOwner) private {
66+
/**
67+
* @dev Transfers ownership of the contract to a new account (`newOwner`).
68+
* Internal function without access restriction.
69+
*/
70+
function _transferOwnership(address newOwner) internal virtual {
6771
address oldOwner = _owner;
6872
_owner = newOwner;
6973
emit OwnershipTransferred(oldOwner, newOwner);

contracts/governance/Governor.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor {
5555
_name = name_;
5656
}
5757

58+
/**
59+
* @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract)
60+
*/
61+
receive() external payable virtual {
62+
require(_executor() == address(this));
63+
}
64+
5865
/**
5966
* @dev See {IERC165-supportsInterface}.
6067
*/

contracts/governance/extensions/GovernorCountingSimple.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ abstract contract GovernorCountingSimple is Governor {
7070
}
7171

7272
/**
73-
* @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be scritly over the againstVotes.
73+
* @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes.
7474
*/
7575
function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
7676
ProposalVote storage proposalvote = _proposalVotes[proposalId];

contracts/governance/extensions/GovernorTimelockCompound.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,9 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor {
177177
) internal virtual override {
178178
uint256 eta = proposalEta(proposalId);
179179
require(eta > 0, "GovernorTimelockCompound: proposal not yet queued");
180+
Address.sendValue(payable(_timelock), msg.value);
180181
for (uint256 i = 0; i < targets.length; ++i) {
181-
_timelock.executeTransaction{value: values[i]}(targets[i], values[i], "", calldatas[i], eta);
182+
_timelock.executeTransaction(targets[i], values[i], "", calldatas[i], eta);
182183
}
183184
}
184185

contracts/mocks/GovernorCompMock.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ contract GovernorCompMock is Governor, GovernorVotesComp, GovernorCountingSimple
2020
_votingPeriod = votingPeriod_;
2121
}
2222

23-
receive() external payable {}
24-
2523
function votingDelay() public view override returns (uint256) {
2624
return _votingDelay;
2725
}

contracts/mocks/GovernorMock.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ contract GovernorMock is Governor, GovernorVotesQuorumFraction, GovernorCounting
2121
_votingPeriod = votingPeriod_;
2222
}
2323

24-
receive() external payable {}
25-
2624
function votingDelay() public view override returns (uint256) {
2725
return _votingDelay;
2826
}

contracts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@openzeppelin/contracts",
33
"description": "Secure Smart Contract library for Solidity",
4-
"version": "4.3.0",
4+
"version": "4.3.2",
55
"files": [
66
"**/*.sol",
77
"/build/contracts/*.json",

contracts/proxy/utils/Initializable.sol

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ pragma solidity ^0.8.0;
1313
*
1414
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
1515
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
16+
*
17+
* [CAUTION]
18+
* ====
19+
* Avoid leaving a contract uninitialized.
20+
*
21+
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
22+
* contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
23+
* initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
24+
*
25+
* [.hljs-theme-light.nopadding]
26+
* ```
27+
* /// @custom:oz-upgrades-unsafe-allow constructor
28+
* constructor() initializer {}
29+
* ```
30+
* ====
1631
*/
1732
abstract contract Initializable {
1833
/**

contracts/proxy/utils/UUPSUpgradeable.sol

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,32 @@ import "../ERC1967/ERC1967Upgrade.sol";
1717
* _Available since v4.1._
1818
*/
1919
abstract contract UUPSUpgradeable is ERC1967Upgrade {
20+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
21+
address private immutable __self = address(this);
22+
23+
/**
24+
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
25+
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
26+
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
27+
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
28+
* fail.
29+
*/
30+
modifier onlyProxy() {
31+
require(address(this) != __self, "Function must be called through delegatecall");
32+
require(_getImplementation() == __self, "Function must be called through active proxy");
33+
_;
34+
}
35+
2036
/**
2137
* @dev Upgrade the implementation of the proxy to `newImplementation`.
2238
*
2339
* Calls {_authorizeUpgrade}.
2440
*
2541
* Emits an {Upgraded} event.
2642
*/
27-
function upgradeTo(address newImplementation) external virtual {
43+
function upgradeTo(address newImplementation) external virtual onlyProxy {
2844
_authorizeUpgrade(newImplementation);
29-
_upgradeToAndCallSecure(newImplementation, bytes(""), false);
45+
_upgradeToAndCallSecure(newImplementation, new bytes(0), false);
3046
}
3147

3248
/**
@@ -37,7 +53,7 @@ abstract contract UUPSUpgradeable is ERC1967Upgrade {
3753
*
3854
* Emits an {Upgraded} event.
3955
*/
40-
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
56+
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
4157
_authorizeUpgrade(newImplementation);
4258
_upgradeToAndCallSecure(newImplementation, data, true);
4359
}

contracts/utils/cryptography/SignatureChecker.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import "../../interfaces/IERC1271.sol";
88

99
/**
1010
* @dev Signature verification helper: Provide a single mechanism to verify both private-key (EOA) ECDSA signature and
11-
* ERC1271 contract sigantures. Using this instead of ECDSA.recover in your contract will make them compatible with
11+
* ERC1271 contract signatures. Using this instead of ECDSA.recover in your contract will make them compatible with
1212
* smart contract wallets such as Argent and Gnosis.
1313
*
1414
* Note: unlike ECDSA signatures, contract signature's are revocable, and the outcome of this function can thus change

docs/modules/ROOT/pages/erc721.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ contract GameItem is ERC721URIStorage {
4040
}
4141
----
4242

43-
The xref:api:token/ERC721.adoc#ERC721URIStorage[`ERC721URIStorage`] contract is an implementation of ERC721 that includes all standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`] and xref:api:token/ERC721.adoc#IERC721Enumerable[`IERC721Enumerable`]). That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata.
43+
The xref:api:token/ERC721.adoc#ERC721URIStorage[`ERC721URIStorage`] contract is an implementation of ERC721 that includes the metadata standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`]) as well as a mechanism for per-token metadata. That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata.
4444

4545
Also note that, unlike ERC20, ERC721 lacks a `decimals` field, since each token is distinct and cannot be partitioned.
4646

docs/modules/ROOT/pages/governance.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, Gove
247247

248248
It is good practice to add a timelock to governance decisions. This allows users to exit the system if they disagree with a decision before it is executed. We will use OpenZeppelin’s TimelockController in combination with the GovernorTimelockControl module.
249249

250+
IMPORTANT: When using a timelock, it is the timelock that will execute proposals and thus the timelock that should hold any funds, ownership, and access control roles. Funds in the Governor contract are not currently retrievable when using a timelock! (As of version 4.3 there is a caveat when using the Compound Timelock: ETH in the timelock is not easily usable, so it is recommended to manage ERC20 funds only in this combination until a future version resolves the issue.)
251+
250252
TimelockController uses an AccessControl setup that we need to understand in order to set up roles. The Proposer role is in charge of queueing operations: this is the role the Governor instance should be granted, and it should likely be the only proposer in the system. The Executor role is in charge of executing already available operations: we can assign this role to the special zero address to allow anyone to execute (if operations can be particularly time sensitive, the Governor should be made Executor instead). Lastly, there is the Admin role, which can grant and revoke the two previous roles: this is a very sensitive role that will be granted automatically to both deployer and timelock itself, but should be renounced by the deployer after setup.
251253

252254
== Proposal Lifecycle

0 commit comments

Comments
 (0)