Skip to content

Commit

Permalink
Split StorageSlot into TransientSlot (#5239)
Browse files Browse the repository at this point in the history
Co-authored-by: Hadrien Croubois <[email protected]>
  • Loading branch information
ernestognw and Amxx authored Oct 8, 2024
1 parent 2bedb02 commit 6325009
Show file tree
Hide file tree
Showing 15 changed files with 434 additions and 333 deletions.
52 changes: 1 addition & 51 deletions contracts/mocks/StorageSlotMock.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/StorageSlotMock.js.

pragma solidity ^0.8.24;
pragma solidity ^0.8.20;

import {Multicall} from "../utils/Multicall.sol";
import {StorageSlot} from "../utils/StorageSlot.sol";
Expand Down Expand Up @@ -84,54 +84,4 @@ contract StorageSlotMock is Multicall {
function getBytesStorage(uint256 key) public view returns (bytes memory) {
return bytesMap[key].getBytesSlot().value;
}

event AddressValue(bytes32 slot, address value);

function tloadAddress(bytes32 slot) public {
emit AddressValue(slot, slot.asAddress().tload());
}

function tstore(bytes32 slot, address value) public {
slot.asAddress().tstore(value);
}

event BooleanValue(bytes32 slot, bool value);

function tloadBoolean(bytes32 slot) public {
emit BooleanValue(slot, slot.asBoolean().tload());
}

function tstore(bytes32 slot, bool value) public {
slot.asBoolean().tstore(value);
}

event Bytes32Value(bytes32 slot, bytes32 value);

function tloadBytes32(bytes32 slot) public {
emit Bytes32Value(slot, slot.asBytes32().tload());
}

function tstore(bytes32 slot, bytes32 value) public {
slot.asBytes32().tstore(value);
}

event Uint256Value(bytes32 slot, uint256 value);

function tloadUint256(bytes32 slot) public {
emit Uint256Value(slot, slot.asUint256().tload());
}

function tstore(bytes32 slot, uint256 value) public {
slot.asUint256().tstore(value);
}

event Int256Value(bytes32 slot, int256 value);

function tloadInt256(bytes32 slot) public {
emit Int256Value(slot, slot.asInt256().tload());
}

function tstore(bytes32 slot, int256 value) public {
slot.asInt256().tstore(value);
}
}
61 changes: 61 additions & 0 deletions contracts/mocks/TransientSlotMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/TransientSlotMock.js.

pragma solidity ^0.8.24;

import {Multicall} from "../utils/Multicall.sol";
import {TransientSlot} from "../utils/TransientSlot.sol";

contract TransientSlotMock is Multicall {
using TransientSlot for *;

event AddressValue(bytes32 slot, address value);

function tloadAddress(bytes32 slot) public {
emit AddressValue(slot, slot.asAddress().tload());
}

function tstore(bytes32 slot, address value) public {
slot.asAddress().tstore(value);
}

event BooleanValue(bytes32 slot, bool value);

function tloadBoolean(bytes32 slot) public {
emit BooleanValue(slot, slot.asBoolean().tload());
}

function tstore(bytes32 slot, bool value) public {
slot.asBoolean().tstore(value);
}

event Bytes32Value(bytes32 slot, bytes32 value);

function tloadBytes32(bytes32 slot) public {
emit Bytes32Value(slot, slot.asBytes32().tload());
}

function tstore(bytes32 slot, bytes32 value) public {
slot.asBytes32().tstore(value);
}

event Uint256Value(bytes32 slot, uint256 value);

function tloadUint256(bytes32 slot) public {
emit Uint256Value(slot, slot.asUint256().tload());
}

function tstore(bytes32 slot, uint256 value) public {
slot.asUint256().tstore(value);
}

event Int256Value(bytes32 slot, int256 value);

function tloadInt256(bytes32 slot) public {
emit Int256Value(slot, slot.asInt256().tload());
}

function tstore(bytes32 slot, int256 value) public {
slot.asInt256().tstore(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {IERC20, ERC20} from "../ERC20.sol";
import {IERC7674} from "../../../interfaces/draft-IERC7674.sol";
import {Math} from "../../../utils/math/Math.sol";
import {SlotDerivation} from "../../../utils/SlotDerivation.sol";
import {StorageSlot} from "../../../utils/StorageSlot.sol";
import {TransientSlot} from "../../../utils/TransientSlot.sol";

/**
* @dev Extension of {ERC20} that adds support for temporary allowances following ERC-7674.
Expand All @@ -17,8 +17,8 @@ import {StorageSlot} from "../../../utils/StorageSlot.sol";
*/
abstract contract ERC20TemporaryApproval is ERC20, IERC7674 {
using SlotDerivation for bytes32;
using StorageSlot for bytes32;
using StorageSlot for StorageSlot.Uint256SlotType;
using TransientSlot for bytes32;
using TransientSlot for TransientSlot.Uint256Slot;

// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20_TEMPORARY_APPROVAL_STORAGE")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC20_TEMPORARY_APPROVAL_STORAGE =
Expand Down Expand Up @@ -112,10 +112,7 @@ abstract contract ERC20TemporaryApproval is ERC20, IERC7674 {
}
}

function _temporaryAllowanceSlot(
address owner,
address spender
) private pure returns (StorageSlot.Uint256SlotType) {
function _temporaryAllowanceSlot(address owner, address spender) private pure returns (TransientSlot.Uint256Slot) {
return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256();
}
}
5 changes: 4 additions & 1 deletion contracts/utils/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ Miscellaneous contracts and libraries containing utility functions you can use t
* {Strings}: Common operations for strings formatting.
* {ShortString}: Library to encode (and decode) short strings into (or from) a single bytes32 slot for optimizing costs. Short strings are limited to 31 characters.
* {SlotDerivation}: Methods for deriving storage slot from ERC-7201 namespaces as well as from constructions such as mapping and arrays.
* {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types. Also include primitives for reading from and writing to transient storage (only value types are currently supported).
* {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types.
* {TransientSlot}: Primitives for reading from and writing to transient storage (only value types are currently supported).
* {Multicall}: Abstract contract with a utility to allow batching together multiple calls in a single transaction. Useful for allowing EOAs to perform multiple operations at once.
* {Context}: A utility for abstracting the sender and calldata in the current execution context.
* {Packing}: A library for packing and unpacking multiple values into bytes32
Expand Down Expand Up @@ -130,6 +131,8 @@ Ethereum contracts have no native concept of an interface, so applications must

{{StorageSlot}}

{{TransientSlot}}

{{Multicall}}

{{Context}}
Expand Down
4 changes: 2 additions & 2 deletions contracts/utils/ReentrancyGuardTransient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity ^0.8.24;

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

/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
Expand All @@ -12,7 +12,7 @@ import {StorageSlot} from "./StorageSlot.sol";
* _Available since v5.1._
*/
abstract contract ReentrancyGuardTransient {
using StorageSlot for *;
using TransientSlot for *;

// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
Expand Down
170 changes: 1 addition & 169 deletions contracts/utils/StorageSlot.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.24;
pragma solidity ^0.8.20;

/**
* @dev Library for reading and writing primitive types to specific storage slots.
Expand All @@ -29,24 +29,6 @@ pragma solidity ^0.8.24;
* }
* ```
*
* Since version 5.1, this library also support writing and reading value types to and from transient storage.
*
* * Example using transient storage:
* ```solidity
* contract Lock {
* // 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 StorageSlot {
Expand Down Expand Up @@ -158,154 +140,4 @@ library StorageSlot {
r.slot := store.slot
}
}

/**
* @dev UDVT that represent a slot holding a address.
*/
type AddressSlotType is bytes32;

/**
* @dev Cast an arbitrary slot to a AddressSlotType.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlotType) {
return AddressSlotType.wrap(slot);
}

/**
* @dev UDVT that represent a slot holding a bool.
*/
type BooleanSlotType is bytes32;

/**
* @dev Cast an arbitrary slot to a BooleanSlotType.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlotType) {
return BooleanSlotType.wrap(slot);
}

/**
* @dev UDVT that represent a slot holding a bytes32.
*/
type Bytes32SlotType is bytes32;

/**
* @dev Cast an arbitrary slot to a Bytes32SlotType.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32SlotType) {
return Bytes32SlotType.wrap(slot);
}

/**
* @dev UDVT that represent a slot holding a uint256.
*/
type Uint256SlotType is bytes32;

/**
* @dev Cast an arbitrary slot to a Uint256SlotType.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256SlotType) {
return Uint256SlotType.wrap(slot);
}

/**
* @dev UDVT that represent a slot holding a int256.
*/
type Int256SlotType is bytes32;

/**
* @dev Cast an arbitrary slot to a Int256SlotType.
*/
function asInt256(bytes32 slot) internal pure returns (Int256SlotType) {
return Int256SlotType.wrap(slot);
}

/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlotType slot) internal view returns (address value) {
assembly ("memory-safe") {
value := tload(slot)
}
}

/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlotType slot, address value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}

/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlotType slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}

/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlotType slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}

/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32SlotType slot) internal view returns (bytes32 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}

/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32SlotType slot, bytes32 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}

/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256SlotType slot) internal view returns (uint256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}

/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256SlotType slot, uint256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}

/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256SlotType slot) internal view returns (int256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}

/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256SlotType slot, int256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}
Loading

0 comments on commit 6325009

Please sign in to comment.