-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #108 from ethstorage/reentrancy
Fix re-entrance
- Loading branch information
Showing
5 changed files
with
494 additions
and
7 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
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(); | ||
} | ||
} |
Oops, something went wrong.