Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/three-parents-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': patch
---

`ReentrancyGuard`, `ReentrancyGuardTransient`: Add an internal `_reentrancyGuardStorageSlot` function allowing slot customization via override.
27 changes: 20 additions & 7 deletions contracts/utils/ReentrancyGuard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";

/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
Expand All @@ -21,8 +23,17 @@ pragma solidity ^0.8.20;
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*
* IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
* by the {ReentrancyGuardTransient} variant in v6.0.
*/
abstract contract ReentrancyGuard {
using StorageSlot for bytes32;

// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
Expand All @@ -37,15 +48,13 @@ abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;

uint256 private _status;

/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();

constructor() {
_status = NOT_ENTERED;
_reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
}

/**
Expand Down Expand Up @@ -75,7 +84,7 @@ abstract contract ReentrancyGuard {
}

function _nonReentrantBeforeView() private view {
if (_status == ENTERED) {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
}
Expand All @@ -85,20 +94,24 @@ abstract contract ReentrancyGuard {
_nonReentrantBeforeView();

// Any calls to nonReentrant after this point will fail
_status = ENTERED;
_reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
}

function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
_reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
}

/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
return _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
}

function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}
10 changes: 7 additions & 3 deletions contracts/utils/ReentrancyGuardTransient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,22 @@ abstract contract ReentrancyGuardTransient {
_nonReentrantBeforeView();

// Any calls to nonReentrant after this point will fail
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
_reentrancyGuardStorageSlot().asBoolean().tstore(true);
}

function _nonReentrantAfter() private {
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
_reentrancyGuardStorageSlot().asBoolean().tstore(false);
}

/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
return _reentrancyGuardStorageSlot().asBoolean().tload();
}

function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}
42 changes: 29 additions & 13 deletions scripts/upgradeable/upgradeable.patch
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ index ff596b0c3..000000000
-<!-- Make sure that you have reviewed the OpenZeppelin Contracts Contributor Guidelines. -->
-<!-- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md -->
diff --git a/README.md b/README.md
index 60d0a430a..0e4f91a6d 100644
index 2f92281b3..a0e46695d 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,9 @@
@@ -20,6 +20,9 @@
> [!IMPORTANT]
> OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/backwards-compatibility).

Expand All @@ -72,7 +72,7 @@ index 60d0a430a..0e4f91a6d 100644
## Overview

### Installation
@@ -26,7 +29,7 @@
@@ -27,7 +30,7 @@
#### Hardhat (npm)

```
Expand All @@ -81,7 +81,7 @@ index 60d0a430a..0e4f91a6d 100644
```

#### Foundry (git)
@@ -38,10 +41,10 @@ $ npm install @openzeppelin/contracts
@@ -39,10 +42,10 @@ $ npm install @openzeppelin/contracts
> Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.

```
Expand All @@ -94,7 +94,7 @@ index 60d0a430a..0e4f91a6d 100644

### Usage

@@ -50,10 +53,11 @@ Once installed, you can use the contracts in the library by importing them:
@@ -51,10 +54,11 @@ Once installed, you can use the contracts in the library by importing them:
```solidity
pragma solidity ^0.8.20;

Expand All @@ -110,15 +110,15 @@ index 60d0a430a..0e4f91a6d 100644
}
```
diff --git a/contracts/package.json b/contracts/package.json
index 70ae73bc2..ef659873f 100644
index 8ccb9465e..509cd7f05 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,5 +1,5 @@
{
- "name": "@openzeppelin/contracts",
+ "name": "@openzeppelin/contracts-upgradeable",
"description": "Secure Smart Contract library for Solidity",
"version": "5.3.0",
"version": "5.4.0",
"files": [
@@ -13,7 +13,7 @@
},
Expand All @@ -139,12 +139,28 @@ index 70ae73bc2..ef659873f 100644
+ "@openzeppelin/contracts": "<package-version>"
+ }
}
diff --git a/contracts/utils/ReentrancyGuard.sol b/contracts/utils/ReentrancyGuard.sol
index f958d5e8f..845209bc8 100644
--- a/contracts/utils/ReentrancyGuard.sol
+++ b/contracts/utils/ReentrancyGuard.sol
@@ -36,6 +36,11 @@ abstract contract ReentrancyGuard {
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

+ /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
+ struct ReentrancyGuardStorage {
+ uint256 _status;
+ }
+
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol
index c39954e35..fe681f87a 100644
index 0eaef9d27..01f1b5f58 100644
--- a/contracts/utils/cryptography/EIP712.sol
+++ b/contracts/utils/cryptography/EIP712.sol
@@ -4,7 +4,6 @@
pragma solidity ^0.8.20;
pragma solidity ^0.8.24;

import {MessageHashUtils} from "./MessageHashUtils.sol";
-import {ShortStrings, ShortString} from "../ShortStrings.sol";
Expand Down Expand Up @@ -314,10 +330,10 @@ index c39954e35..fe681f87a 100644
}
}
diff --git a/package.json b/package.json
index eeeaf0bcd..65581c544 100644
index 285a074ed..d48cc8e4b 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
@@ -35,7 +35,7 @@
},
"repository": {
"type": "git",
Expand All @@ -335,7 +351,7 @@ index 304d1386a..a1cd63bee 100644
+@openzeppelin/contracts-upgradeable/=contracts/
+@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
diff --git a/test/account/AccountERC7702.test.js b/test/account/AccountERC7702.test.js
index d08a52209..7a44bccfe 100644
index f442d49af..8f22dc926 100644
--- a/test/account/AccountERC7702.test.js
+++ b/test/account/AccountERC7702.test.js
@@ -26,8 +26,8 @@ async function fixture() {
Expand All @@ -350,7 +366,7 @@ index d08a52209..7a44bccfe 100644
verifyingContract: mock.address,
};
diff --git a/test/account/examples/AccountERC7702WithModulesMock.test.js b/test/account/examples/AccountERC7702WithModulesMock.test.js
index 9ee5f9177..f6106bcc7 100644
index 8ceab19d1..c3f4194a6 100644
--- a/test/account/examples/AccountERC7702WithModulesMock.test.js
+++ b/test/account/examples/AccountERC7702WithModulesMock.test.js
@@ -36,8 +36,8 @@ async function fixture() {
Expand Down