Skip to content

Commit acdc6a9

Browse files
committed
Merge branch 'master' into structure/merkletree
2 parents f954a98 + 0a757ec commit acdc6a9

File tree

20 files changed

+248
-111
lines changed

20 files changed

+248
-111
lines changed

.changeset/dirty-cobras-smile.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+
`Arrays`: add a `sort` function.

.changeset/gentle-bulldogs-turn.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+
`DoubleEndedQueue`: Custom errors replaced with native panic codes.

.changeset/smart-bugs-switch.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
'openzeppelin-solidity': minor
33
---
44

5-
`Math`: MathOverflowedMulDiv error was replaced with native panic codes.
5+
`Math`: Custom errors replaced with native panic codes.

contracts/mocks/_import.sol

Lines changed: 0 additions & 40 deletions
This file was deleted.

contracts/token/ERC1155/IERC1155.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ interface IERC1155 is IERC165 {
6666
*
6767
* Requirements:
6868
*
69-
* - `operator` cannot be the caller.
69+
* - `operator` cannot be the zero address.
7070
*/
7171
function setApprovalForAll(address operator, bool approved) external;
7272

contracts/utils/Arrays.sol

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,69 @@ import {Math} from "./math/Math.sol";
1212
library Arrays {
1313
using StorageSlot for bytes32;
1414

15+
/**
16+
* @dev Sort an array (in memory) in increasing order.
17+
*
18+
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
19+
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
20+
*
21+
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
22+
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
23+
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
24+
* consume more gas than is available in a block, leading to potential DoS.
25+
*/
26+
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
27+
_quickSort(array, 0, array.length);
28+
return array;
29+
}
30+
31+
/**
32+
* @dev Performs a quick sort on an array in memory. The array is sorted in increasing order.
33+
*
34+
* Invariant: `i <= j <= array.length`. This is the case when initially called by {sort} and is preserved in
35+
* subcalls.
36+
*/
37+
function _quickSort(uint256[] memory array, uint256 i, uint256 j) private pure {
38+
unchecked {
39+
// Can't overflow given `i <= j`
40+
if (j - i < 2) return;
41+
42+
// Use first element as pivot
43+
uint256 pivot = unsafeMemoryAccess(array, i);
44+
// Position where the pivot should be at the end of the loop
45+
uint256 index = i;
46+
47+
for (uint256 k = i + 1; k < j; ++k) {
48+
// Unsafe access is safe given `k < j <= array.length`.
49+
if (unsafeMemoryAccess(array, k) < pivot) {
50+
// If array[k] is smaller than the pivot, we increment the index and move array[k] there.
51+
_swap(array, ++index, k);
52+
}
53+
}
54+
55+
// Swap pivot into place
56+
_swap(array, i, index);
57+
58+
_quickSort(array, i, index); // Sort the left side of the pivot
59+
_quickSort(array, index + 1, j); // Sort the right side of the pivot
60+
}
61+
}
62+
63+
/**
64+
* @dev Swaps the elements at positions `i` and `j` in the `arr` array.
65+
*/
66+
function _swap(uint256[] memory arr, uint256 i, uint256 j) private pure {
67+
assembly {
68+
let start := add(arr, 0x20) // Pointer to the first element of the array
69+
let pos_i := add(start, mul(i, 0x20))
70+
let pos_j := add(start, mul(j, 0x20))
71+
let val_i := mload(pos_i)
72+
let val_j := mload(pos_j)
73+
mstore(pos_i, val_j)
74+
mstore(pos_j, val_i)
75+
}
76+
}
77+
1578
/**
1679
* @dev Searches a sorted `array` and returns the first index that contains
1780
* a value greater or equal to `element`. If no such index exists (i.e. all

contracts/utils/Panic.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pragma solidity ^0.8.20;
1717
* }
1818
* ```
1919
*
20-
* Follows the list from libsolutil: https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h
20+
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
2121
*/
2222
// slither-disable-next-line unused-state
2323
library Panic {

contracts/utils/README.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Miscellaneous contracts and libraries containing utility functions you can use t
2929
* {StorageSlot}: Methods for accessing specific storage slots formatted as common primitive types.
3030
* {Multicall}: Abstract contract with an utility to allow batching together multiple calls in a single transaction. Useful for allowing EOAs to perform multiple operations at once.
3131
* {Context}: An utility for abstracting the sender and calldata in the current execution context.
32+
* {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].
3233

3334
[NOTE]
3435
====
@@ -106,3 +107,5 @@ Ethereum contracts have no native concept of an interface, so applications must
106107
{{Multicall}}
107108

108109
{{Context}}
110+
111+
{{Panic}}

contracts/utils/structs/DoubleEndedQueue.sol

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)
33
pragma solidity ^0.8.20;
44

5+
import {Panic} from "../Panic.sol";
6+
57
/**
68
* @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
79
* the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
@@ -15,21 +17,6 @@ pragma solidity ^0.8.20;
1517
* ```
1618
*/
1719
library DoubleEndedQueue {
18-
/**
19-
* @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
20-
*/
21-
error QueueEmpty();
22-
23-
/**
24-
* @dev A push operation couldn't be completed due to the queue being full.
25-
*/
26-
error QueueFull();
27-
28-
/**
29-
* @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
30-
*/
31-
error QueueOutOfBounds();
32-
3320
/**
3421
* @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
3522
*
@@ -48,12 +35,12 @@ library DoubleEndedQueue {
4835
/**
4936
* @dev Inserts an item at the end of the queue.
5037
*
51-
* Reverts with {QueueFull} if the queue is full.
38+
* Reverts with {Panic-RESOURCE_ERROR} if the queue is full.
5239
*/
5340
function pushBack(Bytes32Deque storage deque, bytes32 value) internal {
5441
unchecked {
5542
uint128 backIndex = deque._end;
56-
if (backIndex + 1 == deque._begin) revert QueueFull();
43+
if (backIndex + 1 == deque._begin) Panic.panic(Panic.RESOURCE_ERROR);
5744
deque._data[backIndex] = value;
5845
deque._end = backIndex + 1;
5946
}
@@ -62,12 +49,12 @@ library DoubleEndedQueue {
6249
/**
6350
* @dev Removes the item at the end of the queue and returns it.
6451
*
65-
* Reverts with {QueueEmpty} if the queue is empty.
52+
* Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty.
6653
*/
6754
function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) {
6855
unchecked {
6956
uint128 backIndex = deque._end;
70-
if (backIndex == deque._begin) revert QueueEmpty();
57+
if (backIndex == deque._begin) Panic.panic(Panic.EMPTY_ARRAY_POP);
7158
--backIndex;
7259
value = deque._data[backIndex];
7360
delete deque._data[backIndex];
@@ -78,12 +65,12 @@ library DoubleEndedQueue {
7865
/**
7966
* @dev Inserts an item at the beginning of the queue.
8067
*
81-
* Reverts with {QueueFull} if the queue is full.
68+
* Reverts with {Panic-RESOURCE_ERROR} if the queue is full.
8269
*/
8370
function pushFront(Bytes32Deque storage deque, bytes32 value) internal {
8471
unchecked {
8572
uint128 frontIndex = deque._begin - 1;
86-
if (frontIndex == deque._end) revert QueueFull();
73+
if (frontIndex == deque._end) Panic.panic(Panic.RESOURCE_ERROR);
8774
deque._data[frontIndex] = value;
8875
deque._begin = frontIndex;
8976
}
@@ -92,12 +79,12 @@ library DoubleEndedQueue {
9279
/**
9380
* @dev Removes the item at the beginning of the queue and returns it.
9481
*
95-
* Reverts with `QueueEmpty` if the queue is empty.
82+
* Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty.
9683
*/
9784
function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) {
9885
unchecked {
9986
uint128 frontIndex = deque._begin;
100-
if (frontIndex == deque._end) revert QueueEmpty();
87+
if (frontIndex == deque._end) Panic.panic(Panic.EMPTY_ARRAY_POP);
10188
value = deque._data[frontIndex];
10289
delete deque._data[frontIndex];
10390
deque._begin = frontIndex + 1;
@@ -107,20 +94,20 @@ library DoubleEndedQueue {
10794
/**
10895
* @dev Returns the item at the beginning of the queue.
10996
*
110-
* Reverts with `QueueEmpty` if the queue is empty.
97+
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty.
11198
*/
11299
function front(Bytes32Deque storage deque) internal view returns (bytes32 value) {
113-
if (empty(deque)) revert QueueEmpty();
100+
if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
114101
return deque._data[deque._begin];
115102
}
116103

117104
/**
118105
* @dev Returns the item at the end of the queue.
119106
*
120-
* Reverts with `QueueEmpty` if the queue is empty.
107+
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty.
121108
*/
122109
function back(Bytes32Deque storage deque) internal view returns (bytes32 value) {
123-
if (empty(deque)) revert QueueEmpty();
110+
if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
124111
unchecked {
125112
return deque._data[deque._end - 1];
126113
}
@@ -130,10 +117,10 @@ library DoubleEndedQueue {
130117
* @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
131118
* `length(deque) - 1`.
132119
*
133-
* Reverts with `QueueOutOfBounds` if the index is out of bounds.
120+
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the index is out of bounds.
134121
*/
135122
function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) {
136-
if (index >= length(deque)) revert QueueOutOfBounds();
123+
if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
137124
// By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
138125
unchecked {
139126
return deque._data[deque._begin + uint128(index)];

docs/templates/contract.hbs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,23 @@ import "@openzeppelin/{{__item_context.file.absolutePath}}";
7474
--
7575
{{/if}}
7676

77+
{{#if has-internal-variables}}
78+
[.contract-index]
79+
.Internal Variables
80+
--
81+
{{#each inheritance}}
82+
{{#unless @first}}
83+
[.contract-subindex-inherited]
84+
.{{name}}
85+
{{/unless}}
86+
{{#each internal-variables}}
87+
* {xref-{{anchor~}} }[`++{{typeDescriptions.typeString}} {{#if constant}}constant{{/if}} {{name}}++`]
88+
{{/each}}
89+
90+
{{/each}}
91+
--
92+
{{/if}}
93+
7794
{{#each modifiers}}
7895
[.contract-item]
7996
[[{{anchor}}]]
@@ -109,3 +126,12 @@ import "@openzeppelin/{{__item_context.file.absolutePath}}";
109126
{{{natspec.dev}}}
110127

111128
{{/each}}
129+
130+
{{#each internal-variables}}
131+
[.contract-item]
132+
[[{{anchor}}]]
133+
==== `{{typeDescriptions.typeString}} [.contract-item-name]#++{{name}}++#` [.item-kind]#internal{{#if constant}} constant{{/if}}#
134+
135+
{{{natspec.dev}}}
136+
137+
{{/each}}

0 commit comments

Comments
 (0)