Add _reentrancyGuardStorageSlot()
Fixes https://github.com/OpenZeppelin/openzeppelin-contracts/issues/5681 for ReentrancyGuardTransient.
This PR introduces a pure virtual function _reentrancyGuardStorageSlot() in ReentrancyGuardTransient.sol, mirroring the pattern used in the upgradeable Initializable.sol
Motivation
As discussed in https://github.com/OpenZeppelin/openzeppelin-contracts/issues/5681, storage slot collisions can occur when using OpenZeppelin contracts in delegatecall-based modular systems (e.g., the Diamond Standard). While this issue was originally raised in the context of upgradeable contracts, ReentrancyGuardTransient.sol in the non-upgradeable repo is in fact already upgrade-safe due to its use of a named storage slot.
Adding _reentrancyGuardStorageSlot() as a pure virtual function allows advanced users to override the default slot location safely in derived contracts, which is essential when using multiple delegatecall modules that each instantiate ReentrancyGuardTransient.
Summary of Changes
- Introduced
_reentrancyGuardStorageSlot(), markedinternal pure virtual - Replaced all direct uses of
REENTRANCY_GUARD_STORAGEwith calls to this new function - No behavioral or storage layout changes; fully backward-compatible
🦋 Changeset detected
Latest commit: 750a60b92d62ecbb87f58a95062cc08bc4e22b67
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 | Patch |
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
Approved, I consider allowing storage slot overridability while keeping the formula pure a good tradeoff between flexibility and security, as mentioned in https://github.com/OpenZeppelin/openzeppelin-contracts/issues/5681#issuecomment-2870284233. Additionally, we will work on the transpiler to ensure this same pattern is correctly applied across the upgradeable contracts.
While this looks good, I'd like to consider a different approach. See https://github.com/OpenZeppelin/openzeppelin-contracts/issues/5681#issuecomment-2911597864
Some notes:
- we agreed on keeping the
_reentrancyGuardStorageSlot()name - for some stupid reason,
ReentrancyGuardTransientUpgradeableis not seen as stateless, and there is an Upgradeable version of it. We should remove it from 6.0 - there is also an upgradeable version of
ReentrancyGuardthat uses namespace storage. If we apply these changes to the "non-transient" version, it would work, but it would also be strange for the upgradeable version. Do we want that ?
Closed in favor of #5892 (cannot modify this PR's code)