Skip to content

Commit 6538427

Browse files
ernestognwAmxxarr00
authored
Add RLP library (#5680)
Co-authored-by: Hadrien Croubois <[email protected]> Co-authored-by: Arr00 <[email protected]>
1 parent 2e5d1eb commit 6538427

File tree

15 files changed

+1045
-20
lines changed

15 files changed

+1045
-20
lines changed

.changeset/itchy-turkeys-allow.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+
`RLP`: Add a library for encoding and decoding data in Ethereum's Recursive Length Prefix format.

.changeset/modern-moments-raise.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+
`Memory`: Add a UDVT for handling slices on memory space similarly to calldata slices.

.changeset/wise-webs-fly.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+
`Accumulators`: A library for merging an arbitrary dynamic number of bytes buffers.

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
### Breaking changes
88

99
- `SignerERC7702` is renamed as `SignerEIP7702`. Imports and inheritance must be updated to that new name and path. Behavior is unmodified.
10-
- Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726))
10+
- Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, `ERC4626` and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726))
1111

1212
### Deprecation
1313

contracts/mocks/Stateless.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity ^0.8.26;
44

55
// We keep these imports and a dummy contract just to we can run the test suite after transpilation.
66

7+
import {Accumulators} from "../utils/structs/Accumulators.sol";
78
import {Address} from "../utils/Address.sol";
89
import {Arrays} from "../utils/Arrays.sol";
910
import {AuthorityUtils} from "../access/manager/AuthorityUtils.sol";
@@ -44,6 +45,7 @@ import {P256} from "../utils/cryptography/P256.sol";
4445
import {Packing} from "../utils/Packing.sol";
4546
import {Panic} from "../utils/Panic.sol";
4647
import {RelayedCall} from "../utils/RelayedCall.sol";
48+
import {RLP} from "../utils/RLP.sol";
4749
import {RSA} from "../utils/cryptography/RSA.sol";
4850
import {SafeCast} from "../utils/math/SafeCast.sol";
4951
import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol";

contracts/token/ERC20/extensions/ERC4626.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/ERC4626.sol)
33

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

66
import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol";
77
import {SafeERC20} from "../utils/SafeERC20.sol";

contracts/utils/Memory.sol

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.20;
3+
pragma solidity ^0.8.24;
4+
5+
import {Panic} from "./Panic.sol";
6+
import {Math} from "./math/Math.sol";
47

58
/**
69
* @dev Utilities to manipulate memory.
710
*
811
* Memory is a contiguous and dynamic byte array in which Solidity stores non-primitive types.
9-
* This library provides functions to manipulate pointers to this dynamic array.
12+
* This library provides functions to manipulate pointers to this dynamic array and work with slices of it.
13+
*
14+
* Slices provide a view into a portion of memory without copying data, enabling efficient substring operations.
1015
*
11-
* WARNING: When manipulating memory, make sure to follow the Solidity documentation
16+
* WARNING: When manipulating memory pointers or slices, make sure to follow the Solidity documentation
1217
* guidelines for https://docs.soliditylang.org/en/v0.8.20/assembly.html#memory-safety[Memory Safety].
1318
*/
1419
library Memory {
@@ -41,4 +46,89 @@ library Memory {
4146
function asPointer(bytes32 value) internal pure returns (Pointer) {
4247
return Pointer.wrap(value);
4348
}
49+
50+
/// @dev Move a pointer forward by a given offset.
51+
function forward(Pointer ptr, uint256 offset) internal pure returns (Pointer) {
52+
return Pointer.wrap(bytes32(uint256(Pointer.unwrap(ptr)) + offset));
53+
}
54+
55+
/// @dev Equality comparator for memory pointers.
56+
function equal(Pointer ptr1, Pointer ptr2) internal pure returns (bool) {
57+
return Pointer.unwrap(ptr1) == Pointer.unwrap(ptr2);
58+
}
59+
60+
type Slice is bytes32;
61+
62+
/// @dev Get a slice representation of a bytes object in memory
63+
function asSlice(bytes memory self) internal pure returns (Slice result) {
64+
assembly ("memory-safe") {
65+
result := or(shl(128, mload(self)), add(self, 0x20))
66+
}
67+
}
68+
69+
/// @dev Returns the length of a given slice (equiv to self.length for calldata slices)
70+
function length(Slice self) internal pure returns (uint256 result) {
71+
assembly ("memory-safe") {
72+
result := shr(128, self)
73+
}
74+
}
75+
76+
/// @dev Offset a memory slice (equivalent to self[start:] for calldata slices)
77+
function slice(Slice self, uint256 offset) internal pure returns (Slice) {
78+
if (offset > length(self)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
79+
return _asSlice(length(self) - offset, forward(_pointer(self), offset));
80+
}
81+
82+
/// @dev Offset and cut a Slice (equivalent to self[start:start+length] for calldata slices)
83+
function slice(Slice self, uint256 offset, uint256 len) internal pure returns (Slice) {
84+
if (offset + len > length(self)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
85+
return _asSlice(len, forward(_pointer(self), offset));
86+
}
87+
88+
/**
89+
* @dev Read a bytes32 buffer from a given Slice at a specific offset
90+
*
91+
* NOTE: If offset > length(slice) - 0x20, part of the return value will be out of bound of the slice. These bytes are zeroed.
92+
*/
93+
function load(Slice self, uint256 offset) internal pure returns (bytes32 value) {
94+
uint256 outOfBoundBytes = Math.saturatingSub(0x20 + offset, length(self));
95+
if (outOfBoundBytes > 0x1f) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
96+
97+
assembly ("memory-safe") {
98+
value := and(mload(add(and(self, shr(128, not(0))), offset)), shl(mul(8, outOfBoundBytes), not(0)))
99+
}
100+
}
101+
102+
/// @dev Extract the data corresponding to a Slice (allocate new memory)
103+
function toBytes(Slice self) internal pure returns (bytes memory result) {
104+
uint256 len = length(self);
105+
Memory.Pointer ptr = _pointer(self);
106+
assembly ("memory-safe") {
107+
result := mload(0x40)
108+
mstore(result, len)
109+
mcopy(add(result, 0x20), ptr, len)
110+
mstore(0x40, add(add(result, len), 0x20))
111+
}
112+
}
113+
114+
/**
115+
* @dev Private helper: create a slice from raw values (length and pointer)
116+
*
117+
* NOTE: this function MUST NOT be called with `len` or `ptr` that exceed `2**128-1`. This should never be
118+
* the case of slices produced by `asSlice(bytes)`, and function that reduce the scope of slices
119+
* (`slice(Slice,uint256)` and `slice(Slice,uint256, uint256)`) should not cause this issue if the parent slice is
120+
* correct.
121+
*/
122+
function _asSlice(uint256 len, Memory.Pointer ptr) private pure returns (Slice result) {
123+
assembly ("memory-safe") {
124+
result := or(shl(128, len), ptr)
125+
}
126+
}
127+
128+
/// @dev Returns the memory location of a given slice (equiv to self.offset for calldata slices)
129+
function _pointer(Slice self) private pure returns (Memory.Pointer result) {
130+
assembly ("memory-safe") {
131+
result := and(self, shr(128, not(0)))
132+
}
133+
}
44134
}

contracts/utils/README.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Miscellaneous contracts and libraries containing utility functions you can use t
1313
* {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions.
1414
* {ReentrancyGuardTransient}: Variant of {ReentrancyGuard} that uses transient storage (https://eips.ethereum.org/EIPS/eip-1153[EIP-1153]).
1515
* {ERC165}, {ERC165Checker}: Utilities for inspecting interfaces supported by contracts.
16+
* {Accumulators}: A library for merging an arbitrary dynamic number of bytes buffers.
1617
* {BitMaps}: A simple library to manage boolean value mapped to a numerical index in an efficient way.
1718
* {Checkpoints}: A data structure to store values mapped to a strictly increasing key. Can be used for storing and accessing values over time.
1819
* {CircularBuffer}: A data structure to store the last N values pushed to it.
@@ -38,6 +39,7 @@ Miscellaneous contracts and libraries containing utility functions you can use t
3839
* {Packing}: A library for packing and unpacking multiple values into bytes32.
3940
* {Panic}: A library to revert with https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require[Solidity panic codes].
4041
* {RelayedCall}: A library for performing calls that use minimal and predictable relayers to hide the sender.
42+
* {RLP}: Library for encoding and decoding data in Ethereum's Recursive Length Prefix format.
4143
* {ShortStrings}: Library to encode (and decode) short strings into (or from) a single bytes32 slot for optimizing costs. Short strings are limited to 31 characters.
4244
* {SlotDerivation}: Methods for deriving storage slot from ERC-7201 namespaces as well as from constructions such as mapping and arrays.
4345
* {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types.
@@ -84,6 +86,8 @@ Ethereum contracts have no native concept of an interface, so applications must
8486

8587
== Data Structures
8688

89+
{{Accumulators}}
90+
8791
{{BitMaps}}
8892

8993
{{Checkpoints}}
@@ -138,6 +142,8 @@ Ethereum contracts have no native concept of an interface, so applications must
138142

139143
{{RelayedCall}}
140144

145+
{{RLP}}
146+
141147
{{ShortStrings}}
142148

143149
{{SlotDerivation}}

0 commit comments

Comments
 (0)