Skip to content

Commit 00882f1

Browse files
Transpile 4ddb8d8fe
1 parent 45636a2 commit 00882f1

17 files changed

+272
-167
lines changed

.changeset/yellow-tables-sell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`SafeERC20`: Document risks of `safeIncreaseAllowance` and `safeDecreaseAllowance` when associated with ERC-7674.

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
### Breaking changes
77

88
- `ERC1967Utils`: Removed duplicate declaration of the `Upgraded`, `AdminChanged` and `BeaconUpgraded` events. These events are still available through the `IERC1967` interface located under the `contracts/interfaces/` directory. Minimum pragma version is now 0.8.21.
9-
- `Governor`, `GovernorCountingSimple`: The `_countVotes` virtual function now returns an `uint256` with the total votes casted. This change allows for more flexibility for partial and fractional voting. Upgrading users may get a compilation error that can be fixed by adding a return statement to the `_countVotes` function.
9+
- `Governor`, `GovernorCountingSimple`: The `_countVote` virtual function now returns an `uint256` with the total votes casted. This change allows for more flexibility for partial and fractional voting. Upgrading users may get a compilation error that can be fixed by adding a return statement to the `_countVote` function.
1010

1111
#### Custom error changes
1212

@@ -71,7 +71,7 @@ This version comes with changes to the custom error identifiers. Contracts previ
7171
- `ReentrancyGuardTransient`: Added a variant of `ReentrancyGuard` that uses transient storage. ([#4988](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4988))
7272
- `Strings`: Added a utility function for converting an address to checksummed string. ([#5067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5067))
7373
- `SlotDerivation`: Add a library of methods for derivating common storage slots. ([#4975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4975))
74-
- `StorageSlot`: Add primitives for operating on the transient storage space using a typed-slot representation. ([#4980](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4980))
74+
- `TransientSlot`: Add primitives for operating on the transient storage space using a typed-slot representation. ([#4980](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4980))
7575

7676
##### Cryptography
7777

contracts/mocks/StorageSlotMockUpgradeable.sol

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// This file was procedurally generated from scripts/generate/templates/StorageSlotMock.js.
33

4-
pragma solidity ^0.8.24;
4+
pragma solidity ^0.8.20;
55

66
import {MulticallUpgradeable} from "../utils/MulticallUpgradeable.sol";
77
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
@@ -90,54 +90,4 @@ contract StorageSlotMockUpgradeable is Initializable, MulticallUpgradeable {
9090
function getBytesStorage(uint256 key) public view returns (bytes memory) {
9191
return bytesMap[key].getBytesSlot().value;
9292
}
93-
94-
event AddressValue(bytes32 slot, address value);
95-
96-
function tloadAddress(bytes32 slot) public {
97-
emit AddressValue(slot, slot.asAddress().tload());
98-
}
99-
100-
function tstore(bytes32 slot, address value) public {
101-
slot.asAddress().tstore(value);
102-
}
103-
104-
event BooleanValue(bytes32 slot, bool value);
105-
106-
function tloadBoolean(bytes32 slot) public {
107-
emit BooleanValue(slot, slot.asBoolean().tload());
108-
}
109-
110-
function tstore(bytes32 slot, bool value) public {
111-
slot.asBoolean().tstore(value);
112-
}
113-
114-
event Bytes32Value(bytes32 slot, bytes32 value);
115-
116-
function tloadBytes32(bytes32 slot) public {
117-
emit Bytes32Value(slot, slot.asBytes32().tload());
118-
}
119-
120-
function tstore(bytes32 slot, bytes32 value) public {
121-
slot.asBytes32().tstore(value);
122-
}
123-
124-
event Uint256Value(bytes32 slot, uint256 value);
125-
126-
function tloadUint256(bytes32 slot) public {
127-
emit Uint256Value(slot, slot.asUint256().tload());
128-
}
129-
130-
function tstore(bytes32 slot, uint256 value) public {
131-
slot.asUint256().tstore(value);
132-
}
133-
134-
event Int256Value(bytes32 slot, int256 value);
135-
136-
function tloadInt256(bytes32 slot) public {
137-
emit Int256Value(slot, slot.asInt256().tload());
138-
}
139-
140-
function tstore(bytes32 slot, int256 value) public {
141-
slot.asInt256().tstore(value);
142-
}
14393
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: MIT
2+
// This file was procedurally generated from scripts/generate/templates/TransientSlotMock.js.
3+
4+
pragma solidity ^0.8.24;
5+
6+
import {MulticallUpgradeable} from "../utils/MulticallUpgradeable.sol";
7+
import {TransientSlot} from "@openzeppelin/contracts/utils/TransientSlot.sol";
8+
import {Initializable} from "../proxy/utils/Initializable.sol";
9+
10+
contract TransientSlotMockUpgradeable is Initializable, MulticallUpgradeable {
11+
using TransientSlot for *;
12+
13+
event AddressValue(bytes32 slot, address value);
14+
15+
function __TransientSlotMock_init() internal onlyInitializing {
16+
}
17+
18+
function __TransientSlotMock_init_unchained() internal onlyInitializing {
19+
}
20+
function tloadAddress(bytes32 slot) public {
21+
emit AddressValue(slot, slot.asAddress().tload());
22+
}
23+
24+
function tstore(bytes32 slot, address value) public {
25+
slot.asAddress().tstore(value);
26+
}
27+
28+
event BooleanValue(bytes32 slot, bool value);
29+
30+
function tloadBoolean(bytes32 slot) public {
31+
emit BooleanValue(slot, slot.asBoolean().tload());
32+
}
33+
34+
function tstore(bytes32 slot, bool value) public {
35+
slot.asBoolean().tstore(value);
36+
}
37+
38+
event Bytes32Value(bytes32 slot, bytes32 value);
39+
40+
function tloadBytes32(bytes32 slot) public {
41+
emit Bytes32Value(slot, slot.asBytes32().tload());
42+
}
43+
44+
function tstore(bytes32 slot, bytes32 value) public {
45+
slot.asBytes32().tstore(value);
46+
}
47+
48+
event Uint256Value(bytes32 slot, uint256 value);
49+
50+
function tloadUint256(bytes32 slot) public {
51+
emit Uint256Value(slot, slot.asUint256().tload());
52+
}
53+
54+
function tstore(bytes32 slot, uint256 value) public {
55+
slot.asUint256().tstore(value);
56+
}
57+
58+
event Int256Value(bytes32 slot, int256 value);
59+
60+
function tloadInt256(bytes32 slot) public {
61+
emit Int256Value(slot, slot.asInt256().tload());
62+
}
63+
64+
function tstore(bytes32 slot, int256 value) public {
65+
slot.asInt256().tstore(value);
66+
}
67+
}

contracts/mocks/WithInit.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,13 @@ contract ERC721URIStorageMockUpgradeableWithInit is ERC721URIStorageMockUpgradea
864864
__ERC721URIStorageMock_init();
865865
}
866866
}
867+
import "./TransientSlotMockUpgradeable.sol";
868+
869+
contract TransientSlotMockUpgradeableWithInit is TransientSlotMockUpgradeable {
870+
constructor() payable initializer {
871+
__TransientSlotMock_init();
872+
}
873+
}
867874
import "./UpgradeableBeaconMockUpgradeable.sol";
868875

869876
contract UpgradeableBeaconMockUpgradeableWithInit is UpgradeableBeaconMockUpgradeable {

contracts/token/ERC20/extensions/draft-ERC20TemporaryApprovalUpgradeable.sol

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
88
import {IERC7674} from "@openzeppelin/contracts/interfaces/draft-IERC7674.sol";
99
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
1010
import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol";
11-
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
11+
import {TransientSlot} from "@openzeppelin/contracts/utils/TransientSlot.sol";
1212
import {Initializable} from "../../../proxy/utils/Initializable.sol";
1313

1414
/**
@@ -20,8 +20,8 @@ import {Initializable} from "../../../proxy/utils/Initializable.sol";
2020
*/
2121
abstract contract ERC20TemporaryApprovalUpgradeable is Initializable, ERC20Upgradeable, IERC7674 {
2222
using SlotDerivation for bytes32;
23-
using StorageSlot for bytes32;
24-
using StorageSlot for StorageSlot.Uint256SlotType;
23+
using TransientSlot for bytes32;
24+
using TransientSlot for TransientSlot.Uint256Slot;
2525

2626
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20_TEMPORARY_APPROVAL_STORAGE")) - 1)) & ~bytes32(uint256(0xff))
2727
bytes32 private constant ERC20_TEMPORARY_APPROVAL_STORAGE =
@@ -120,10 +120,7 @@ abstract contract ERC20TemporaryApprovalUpgradeable is Initializable, ERC20Upgra
120120
}
121121
}
122122

123-
function _temporaryAllowanceSlot(
124-
address owner,
125-
address spender
126-
) private pure returns (StorageSlot.Uint256SlotType) {
123+
function _temporaryAllowanceSlot(address owner, address spender) private pure returns (TransientSlot.Uint256Slot) {
127124
return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256();
128125
}
129126
}

contracts/utils/README.adoc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ Miscellaneous contracts and libraries containing utility functions you can use t
3434
* {Strings}: Common operations for strings formatting.
3535
* {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.
3636
* {SlotDerivation}: Methods for deriving storage slot from ERC-7201 namespaces as well as from constructions such as mapping and arrays.
37-
* {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).
37+
* {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types.
38+
* {TransientSlot}: Primitives for reading from and writing to transient storage (only value types are currently supported).
3839
* {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.
3940
* {Context}: A utility for abstracting the sender and calldata in the current execution context.
4041
* {Packing}: A library for packing and unpacking multiple values into bytes32
@@ -130,6 +131,8 @@ Ethereum contracts have no native concept of an interface, so applications must
130131

131132
{{StorageSlot}}
132133

134+
{{TransientSlot}}
135+
133136
{{Multicall}}
134137

135138
{{Context}}

contracts/utils/ReentrancyGuardTransientUpgradeable.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
pragma solidity ^0.8.24;
55

6-
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
6+
import {TransientSlot} from "@openzeppelin/contracts/utils/TransientSlot.sol";
77
import {Initializable} from "../proxy/utils/Initializable.sol";
88

99
/**
@@ -14,7 +14,7 @@ import {Initializable} from "../proxy/utils/Initializable.sol";
1414
* _Available since v5.1._
1515
*/
1616
abstract contract ReentrancyGuardTransientUpgradeable is Initializable {
17-
using StorageSlot for *;
17+
using TransientSlot for *;
1818

1919
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
2020
bytes32 private constant REENTRANCY_GUARD_STORAGE =

docs/modules/ROOT/pages/utilities.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ function _setImplementation(address newImplementation) internal {
319319
}
320320
----
321321

322-
The xref:api:utils.adoc#StorageSlot[`StorageSlot`] library also supports transient storage through user defined value types (https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types[UDVTs]), which enables the same value types as in Solidity.
322+
The xref:api:utils.adoc#TransientSlot[`TransientSlot`] library supports transient storage through user defined value types (https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types[UDVTs]), which enables the same value types as in Solidity.
323323

324324
[source,solidity]
325325
----

scripts/generate/run.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ for (const [file, template] of Object.entries({
3939
'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js',
4040
'utils/SlotDerivation.sol': './templates/SlotDerivation.js',
4141
'utils/StorageSlot.sol': './templates/StorageSlot.js',
42+
'utils/TransientSlot.sol': './templates/TransientSlot.js',
4243
'utils/Arrays.sol': './templates/Arrays.js',
4344
'utils/Packing.sol': './templates/Packing.js',
4445
'mocks/StorageSlotMock.sol': './templates/StorageSlotMock.js',
46+
'mocks/TransientSlotMock.sol': './templates/TransientSlotMock.js',
4547
})) {
4648
generateFromTemplate(file, template, './contracts/');
4749
}

scripts/generate/templates/StorageSlot.js

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const format = require('../format-lines');
22
const { TYPES } = require('./Slot.opts');
33

44
const header = `\
5-
pragma solidity ^0.8.24;
5+
pragma solidity ^0.8.20;
66
77
/**
88
* @dev Library for reading and writing primitive types to specific storage slots.
@@ -29,24 +29,6 @@ pragma solidity ^0.8.24;
2929
* }
3030
* \`\`\`
3131
*
32-
* Since version 5.1, this library also support writing and reading value types to and from transient storage.
33-
*
34-
* * Example using transient storage:
35-
* \`\`\`solidity
36-
* contract Lock {
37-
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
38-
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
39-
*
40-
* modifier locked() {
41-
* require(!_LOCK_SLOT.asBoolean().tload());
42-
*
43-
* _LOCK_SLOT.asBoolean().tstore(true);
44-
* _;
45-
* _LOCK_SLOT.asBoolean().tstore(false);
46-
* }
47-
* }
48-
* \`\`\`
49-
*
5032
* TIP: Consider using this library along with {SlotDerivation}.
5133
*/
5234
`;
@@ -81,40 +63,6 @@ function get${name}Slot(${type} storage store) internal pure returns (${name}Slo
8163
}
8264
`;
8365

84-
const udvt = ({ type, name }) => `\
85-
/**
86-
* @dev UDVT that represent a slot holding a ${type}.
87-
*/
88-
type ${name}SlotType is bytes32;
89-
90-
/**
91-
* @dev Cast an arbitrary slot to a ${name}SlotType.
92-
*/
93-
function as${name}(bytes32 slot) internal pure returns (${name}SlotType) {
94-
return ${name}SlotType.wrap(slot);
95-
}
96-
`;
97-
98-
const transient = ({ type, name }) => `\
99-
/**
100-
* @dev Load the value held at location \`slot\` in transient storage.
101-
*/
102-
function tload(${name}SlotType slot) internal view returns (${type} value) {
103-
assembly ("memory-safe") {
104-
value := tload(slot)
105-
}
106-
}
107-
108-
/**
109-
* @dev Store \`value\` at location \`slot\` in transient storage.
110-
*/
111-
function tstore(${name}SlotType slot, ${type} value) internal {
112-
assembly ("memory-safe") {
113-
tstore(slot, value)
114-
}
115-
}
116-
`;
117-
11866
// GENERATE
11967
module.exports = format(
12068
header.trimEnd(),
@@ -123,8 +71,6 @@ module.exports = format(
12371
[].concat(
12472
TYPES.map(type => struct(type)),
12573
TYPES.flatMap(type => [get(type), !type.isValueType && getStorage(type)].filter(Boolean)),
126-
TYPES.filter(type => type.isValueType).map(type => udvt(type)),
127-
TYPES.filter(type => type.isValueType).map(type => transient(type)),
12874
),
12975
).trimEnd(),
13076
'}',

scripts/generate/templates/StorageSlotMock.js

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const format = require('../format-lines');
22
const { TYPES } = require('./Slot.opts');
33

44
const header = `\
5-
pragma solidity ^0.8.24;
5+
pragma solidity ^0.8.20;
66
77
import {Multicall} from "../utils/Multicall.sol";
88
import {StorageSlot} from "../utils/StorageSlot.sol";
@@ -40,18 +40,6 @@ function get${name}Storage(uint256 key) public view returns (${type} memory) {
4040
}
4141
`;
4242

43-
const transient = ({ type, name }) => `\
44-
event ${name}Value(bytes32 slot, ${type} value);
45-
46-
function tload${name}(bytes32 slot) public {
47-
emit ${name}Value(slot, slot.as${name}().tload());
48-
}
49-
50-
function tstore(bytes32 slot, ${type} value) public {
51-
slot.as${name}().tstore(value);
52-
}
53-
`;
54-
5543
// GENERATE
5644
module.exports = format(
5745
header,
@@ -63,7 +51,6 @@ module.exports = format(
6351
TYPES.filter(type => type.isValueType).map(type => storageSetValueType(type)),
6452
TYPES.filter(type => type.isValueType).map(type => storageGetValueType(type)),
6553
TYPES.filter(type => !type.isValueType).map(type => storageSetNonValueType(type)),
66-
TYPES.filter(type => type.isValueType).map(type => transient(type)),
6754
),
6855
).trimEnd(),
6956
'}',

0 commit comments

Comments
 (0)