-
Notifications
You must be signed in to change notification settings - Fork 11.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Transient version of ReentrancyGuard (#4988)
Co-authored-by: ernestognw <ernestognw@gmail.com>
- Loading branch information
1 parent
8a7a9c5
commit b6e0791
Showing
6 changed files
with
164 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'openzeppelin-solidity': minor | ||
--- | ||
|
||
`ReentrancyGuardTransient`: Added a variant of `ReentrancyGuard` that uses transient storage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.24; | ||
|
||
import {ReentrancyGuardTransient} from "../utils/ReentrancyGuardTransient.sol"; | ||
import {ReentrancyAttack} from "./ReentrancyAttack.sol"; | ||
|
||
contract ReentrancyTransientMock is ReentrancyGuardTransient { | ||
uint256 public counter; | ||
|
||
constructor() { | ||
counter = 0; | ||
} | ||
|
||
function callback() external nonReentrant { | ||
_count(); | ||
} | ||
|
||
function countLocalRecursive(uint256 n) public nonReentrant { | ||
if (n > 0) { | ||
_count(); | ||
countLocalRecursive(n - 1); | ||
} | ||
} | ||
|
||
function countThisRecursive(uint256 n) public nonReentrant { | ||
if (n > 0) { | ||
_count(); | ||
(bool success, ) = address(this).call(abi.encodeCall(this.countThisRecursive, (n - 1))); | ||
require(success, "ReentrancyTransientMock: failed call"); | ||
} | ||
} | ||
|
||
function countAndCall(ReentrancyAttack attacker) public nonReentrant { | ||
_count(); | ||
attacker.callSender(abi.encodeCall(this.callback, ())); | ||
} | ||
|
||
function _count() private { | ||
counter += 1; | ||
} | ||
|
||
function guardedCheckEntered() public nonReentrant { | ||
require(_reentrancyGuardEntered()); | ||
} | ||
|
||
function unguardedCheckNotEntered() public view { | ||
require(!_reentrancyGuardEntered()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.24; | ||
|
||
import {StorageSlot} from "./StorageSlot.sol"; | ||
|
||
/** | ||
* @dev Variant of {ReentrancyGuard} that uses transient storage. | ||
* | ||
* NOTE: This variant only works on networks where EIP-1153 is available. | ||
*/ | ||
abstract contract ReentrancyGuardTransient { | ||
using StorageSlot for *; | ||
|
||
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) | ||
bytes32 private constant REENTRANCY_GUARD_STORAGE = | ||
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; | ||
|
||
/** | ||
* @dev Unauthorized reentrant call. | ||
*/ | ||
error ReentrancyGuardReentrantCall(); | ||
|
||
/** | ||
* @dev Prevents a contract from calling itself, directly or indirectly. | ||
* Calling a `nonReentrant` function from another `nonReentrant` | ||
* function is not supported. It is possible to prevent this from happening | ||
* by making the `nonReentrant` function external, and making it call a | ||
* `private` function that does the actual work. | ||
*/ | ||
modifier nonReentrant() { | ||
_nonReentrantBefore(); | ||
_; | ||
_nonReentrantAfter(); | ||
} | ||
|
||
function _nonReentrantBefore() private { | ||
// On the first call to nonReentrant, _status will be NOT_ENTERED | ||
if (_reentrancyGuardEntered()) { | ||
revert ReentrancyGuardReentrantCall(); | ||
} | ||
|
||
// Any calls to nonReentrant after this point will fail | ||
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); | ||
} | ||
|
||
function _nonReentrantAfter() private { | ||
REENTRANCY_GUARD_STORAGE.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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters