-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Transient storage implementation #31
Open
Debugger022
wants to merge
6
commits into
develop
Choose a base branch
from
feat/transient-storage
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
d7ebaf7
chore: update hardhat config and dependencies to support cancun VM ve…
Debugger022 2d01bec
feat: reentrancy guard using transient storage
Debugger022 c3fd05a
fix: upgrade node version from 18 to 20 in ci.yaml
Debugger022 e24a275
chore: upgrade smock dependency version
Debugger022 2e43a2d
fix: pin smock and hardhat versions
coreyar 74217d1
chore: upgrade hardhat and smock dependency version
Debugger022 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,61 @@ | ||
// SPDX-License-Identifier: MIT | ||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol) | ||
|
||
pragma solidity ^0.8.25; | ||
|
||
import { TransientSlot } from "./TransientSlot.sol"; | ||
|
||
/** | ||
* @dev Variant of {ReentrancyGuard} that uses transient storage. | ||
* | ||
* NOTE: This variant only works on networks where EIP-1153 is available. | ||
* | ||
* _Available since v5.1._ | ||
*/ | ||
abstract contract ReentrancyGuardTransient { | ||
using TransientSlot 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(); | ||
} | ||
|
||
/** | ||
* @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(); | ||
} | ||
|
||
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); | ||
} | ||
} |
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,182 @@ | ||
// SPDX-License-Identifier: MIT | ||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol) | ||
|
||
pragma solidity ^0.8.25; | ||
|
||
/** | ||
* @dev Library for reading and writing value-types to specific transient storage slots. | ||
* | ||
* Transient slots are often used to store temporary values that are removed after the current transaction. | ||
* This library helps with reading and writing to such slots without the need for inline assembly. | ||
* | ||
* * Example reading and writing values using transient storage: | ||
* ```solidity | ||
* contract Lock { | ||
* using TransientSlot for *; | ||
* | ||
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. | ||
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; | ||
* | ||
* modifier locked() { | ||
* require(!_LOCK_SLOT.asBoolean().tload()); | ||
* | ||
* _LOCK_SLOT.asBoolean().tstore(true); | ||
* _; | ||
* _LOCK_SLOT.asBoolean().tstore(false); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* TIP: Consider using this library along with {SlotDerivation}. | ||
*/ | ||
library TransientSlot { | ||
/** | ||
* @dev UDVT that represent a slot holding a address. | ||
*/ | ||
type AddressSlot is bytes32; | ||
|
||
/** | ||
* @dev Cast an arbitrary slot to a AddressSlot. | ||
*/ | ||
function asAddress(bytes32 slot) internal pure returns (AddressSlot) { | ||
return AddressSlot.wrap(slot); | ||
} | ||
|
||
/** | ||
* @dev UDVT that represent a slot holding a bool. | ||
*/ | ||
type BooleanSlot is bytes32; | ||
|
||
/** | ||
* @dev Cast an arbitrary slot to a BooleanSlot. | ||
*/ | ||
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) { | ||
return BooleanSlot.wrap(slot); | ||
} | ||
|
||
/** | ||
* @dev UDVT that represent a slot holding a bytes32. | ||
*/ | ||
type Bytes32Slot is bytes32; | ||
|
||
/** | ||
* @dev Cast an arbitrary slot to a Bytes32Slot. | ||
*/ | ||
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) { | ||
return Bytes32Slot.wrap(slot); | ||
} | ||
|
||
/** | ||
* @dev UDVT that represent a slot holding a uint256. | ||
*/ | ||
type Uint256Slot is bytes32; | ||
|
||
/** | ||
* @dev Cast an arbitrary slot to a Uint256Slot. | ||
*/ | ||
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) { | ||
return Uint256Slot.wrap(slot); | ||
} | ||
|
||
/** | ||
* @dev UDVT that represent a slot holding a int256. | ||
*/ | ||
type Int256Slot is bytes32; | ||
|
||
/** | ||
* @dev Cast an arbitrary slot to a Int256Slot. | ||
*/ | ||
function asInt256(bytes32 slot) internal pure returns (Int256Slot) { | ||
return Int256Slot.wrap(slot); | ||
} | ||
|
||
/** | ||
* @dev Load the value held at location `slot` in transient storage. | ||
*/ | ||
function tload(AddressSlot slot) internal view returns (address value) { | ||
assembly ("memory-safe") { | ||
value := tload(slot) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Store `value` at location `slot` in transient storage. | ||
*/ | ||
function tstore(AddressSlot slot, address value) internal { | ||
assembly ("memory-safe") { | ||
tstore(slot, value) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Load the value held at location `slot` in transient storage. | ||
*/ | ||
function tload(BooleanSlot slot) internal view returns (bool value) { | ||
assembly ("memory-safe") { | ||
value := tload(slot) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Store `value` at location `slot` in transient storage. | ||
*/ | ||
function tstore(BooleanSlot slot, bool value) internal { | ||
assembly ("memory-safe") { | ||
tstore(slot, value) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Load the value held at location `slot` in transient storage. | ||
*/ | ||
function tload(Bytes32Slot slot) internal view returns (bytes32 value) { | ||
assembly ("memory-safe") { | ||
value := tload(slot) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Store `value` at location `slot` in transient storage. | ||
*/ | ||
function tstore(Bytes32Slot slot, bytes32 value) internal { | ||
assembly ("memory-safe") { | ||
tstore(slot, value) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Load the value held at location `slot` in transient storage. | ||
*/ | ||
function tload(Uint256Slot slot) internal view returns (uint256 value) { | ||
assembly ("memory-safe") { | ||
value := tload(slot) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Store `value` at location `slot` in transient storage. | ||
*/ | ||
function tstore(Uint256Slot slot, uint256 value) internal { | ||
assembly ("memory-safe") { | ||
tstore(slot, value) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Load the value held at location `slot` in transient storage. | ||
*/ | ||
function tload(Int256Slot slot) internal view returns (int256 value) { | ||
assembly ("memory-safe") { | ||
value := tload(slot) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Store `value` at location `slot` in transient storage. | ||
*/ | ||
function tstore(Int256Slot slot, int256 value) internal { | ||
assembly ("memory-safe") { | ||
tstore(slot, value) | ||
} | ||
} | ||
} |
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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Support:
AFAIU, ZKSync era doesn't support transient storage yet: