dexorder
This commit is contained in:
151
lib_openzeppelin_contracts/contracts/utils/Address.sol
Normal file
151
lib_openzeppelin_contracts/contracts/utils/Address.sol
Normal file
@@ -0,0 +1,151 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Errors} from "./Errors.sol";
|
||||
|
||||
/**
|
||||
* @dev Collection of functions related to the address type
|
||||
*/
|
||||
library Address {
|
||||
/**
|
||||
* @dev There's no code at `target` (it is not a contract).
|
||||
*/
|
||||
error AddressEmptyCode(address target);
|
||||
|
||||
/**
|
||||
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
|
||||
* `recipient`, forwarding all available gas and reverting on errors.
|
||||
*
|
||||
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
|
||||
* of certain opcodes, possibly making contracts go over the 2300 gas limit
|
||||
* imposed by `transfer`, making them unable to receive funds via
|
||||
* `transfer`. {sendValue} removes this limitation.
|
||||
*
|
||||
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
|
||||
*
|
||||
* IMPORTANT: because control is transferred to `recipient`, care must be
|
||||
* taken to not create reentrancy vulnerabilities. Consider using
|
||||
* {ReentrancyGuard} or the
|
||||
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
|
||||
*/
|
||||
function sendValue(address payable recipient, uint256 amount) internal {
|
||||
if (address(this).balance < amount) {
|
||||
revert Errors.InsufficientBalance(address(this).balance, amount);
|
||||
}
|
||||
|
||||
(bool success, ) = recipient.call{value: amount}("");
|
||||
if (!success) {
|
||||
revert Errors.FailedCall();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Performs a Solidity function call using a low level `call`. A
|
||||
* plain `call` is an unsafe replacement for a function call: use this
|
||||
* function instead.
|
||||
*
|
||||
* If `target` reverts with a revert reason or custom error, it is bubbled
|
||||
* up by this function (like regular Solidity function calls). However, if
|
||||
* the call reverted with no returned reason, this function reverts with a
|
||||
* {Errors.FailedCall} error.
|
||||
*
|
||||
* Returns the raw returned data. To convert to the expected return value,
|
||||
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `target` must be a contract.
|
||||
* - calling `target` with `data` must not revert.
|
||||
*/
|
||||
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
|
||||
return functionCallWithValue(target, data, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
|
||||
* but also transferring `value` wei to `target`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the calling contract must have an ETH balance of at least `value`.
|
||||
* - the called Solidity function must be `payable`.
|
||||
*/
|
||||
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
|
||||
if (address(this).balance < value) {
|
||||
revert Errors.InsufficientBalance(address(this).balance, value);
|
||||
}
|
||||
(bool success, bytes memory returndata) = target.call{value: value}(data);
|
||||
return verifyCallResultFromTarget(target, success, returndata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
|
||||
* but performing a static call.
|
||||
*/
|
||||
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
|
||||
(bool success, bytes memory returndata) = target.staticcall(data);
|
||||
return verifyCallResultFromTarget(target, success, returndata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
|
||||
* but performing a delegate call.
|
||||
*/
|
||||
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
|
||||
(bool success, bytes memory returndata) = target.delegatecall(data);
|
||||
return verifyCallResultFromTarget(target, success, returndata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
|
||||
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
|
||||
* of an unsuccessful call.
|
||||
*/
|
||||
function verifyCallResultFromTarget(
|
||||
address target,
|
||||
bool success,
|
||||
bytes memory returndata
|
||||
) internal view returns (bytes memory) {
|
||||
if (!success) {
|
||||
_revert(returndata);
|
||||
} else {
|
||||
// only check if target is a contract if the call was successful and the return data is empty
|
||||
// otherwise we already know that it was a contract
|
||||
if (returndata.length == 0 && target.code.length == 0) {
|
||||
revert AddressEmptyCode(target);
|
||||
}
|
||||
return returndata;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
|
||||
* revert reason or with a default {Errors.FailedCall} error.
|
||||
*/
|
||||
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
|
||||
if (!success) {
|
||||
_revert(returndata);
|
||||
} else {
|
||||
return returndata;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
|
||||
*/
|
||||
function _revert(bytes memory returndata) private pure {
|
||||
// Look for revert reason and bubble it up if present
|
||||
if (returndata.length > 0) {
|
||||
// The easiest way to bubble the revert reason is using memory via assembly
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let returndata_size := mload(returndata)
|
||||
revert(add(32, returndata), returndata_size)
|
||||
}
|
||||
} else {
|
||||
revert Errors.FailedCall();
|
||||
}
|
||||
}
|
||||
}
|
||||
487
lib_openzeppelin_contracts/contracts/utils/Arrays.sol
Normal file
487
lib_openzeppelin_contracts/contracts/utils/Arrays.sol
Normal file
@@ -0,0 +1,487 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {SlotDerivation} from "./SlotDerivation.sol";
|
||||
import {StorageSlot} from "./StorageSlot.sol";
|
||||
import {Math} from "./math/Math.sol";
|
||||
|
||||
/**
|
||||
* @dev Collection of functions related to array types.
|
||||
*/
|
||||
library Arrays {
|
||||
using SlotDerivation for bytes32;
|
||||
using StorageSlot for bytes32;
|
||||
|
||||
/**
|
||||
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
|
||||
*
|
||||
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
|
||||
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
|
||||
*
|
||||
* 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
|
||||
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
|
||||
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
|
||||
* consume more gas than is available in a block, leading to potential DoS.
|
||||
*/
|
||||
function sort(
|
||||
bytes32[] memory array,
|
||||
function(bytes32, bytes32) pure returns (bool) comp
|
||||
) internal pure returns (bytes32[] memory) {
|
||||
_quickSort(_begin(array), _end(array), comp);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
|
||||
*/
|
||||
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
|
||||
sort(array, _defaultComp);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sort an array of address (in memory) following the provided comparator function.
|
||||
*
|
||||
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
|
||||
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
|
||||
*
|
||||
* 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
|
||||
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
|
||||
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
|
||||
* consume more gas than is available in a block, leading to potential DoS.
|
||||
*/
|
||||
function sort(
|
||||
address[] memory array,
|
||||
function(address, address) pure returns (bool) comp
|
||||
) internal pure returns (address[] memory) {
|
||||
sort(_castToBytes32Array(array), _castToBytes32Comp(comp));
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {sort} that sorts an array of address in increasing order.
|
||||
*/
|
||||
function sort(address[] memory array) internal pure returns (address[] memory) {
|
||||
sort(_castToBytes32Array(array), _defaultComp);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
|
||||
*
|
||||
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
|
||||
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
|
||||
*
|
||||
* 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
|
||||
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
|
||||
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
|
||||
* consume more gas than is available in a block, leading to potential DoS.
|
||||
*/
|
||||
function sort(
|
||||
uint256[] memory array,
|
||||
function(uint256, uint256) pure returns (bool) comp
|
||||
) internal pure returns (uint256[] memory) {
|
||||
sort(_castToBytes32Array(array), _castToBytes32Comp(comp));
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
|
||||
*/
|
||||
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
|
||||
sort(_castToBytes32Array(array), _defaultComp);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
|
||||
* at end (exclusive). Sorting follows the `comp` comparator.
|
||||
*
|
||||
* Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
|
||||
*
|
||||
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
|
||||
* be used only if the limits are within a memory array.
|
||||
*/
|
||||
function _quickSort(uint256 begin, uint256 end, function(bytes32, bytes32) pure returns (bool) comp) private pure {
|
||||
unchecked {
|
||||
if (end - begin < 0x40) return;
|
||||
|
||||
// Use first element as pivot
|
||||
bytes32 pivot = _mload(begin);
|
||||
// Position where the pivot should be at the end of the loop
|
||||
uint256 pos = begin;
|
||||
|
||||
for (uint256 it = begin + 0x20; it < end; it += 0x20) {
|
||||
if (comp(_mload(it), pivot)) {
|
||||
// If the value stored at the iterator's position comes before the pivot, we increment the
|
||||
// position of the pivot and move the value there.
|
||||
pos += 0x20;
|
||||
_swap(pos, it);
|
||||
}
|
||||
}
|
||||
|
||||
_swap(begin, pos); // Swap pivot into place
|
||||
_quickSort(begin, pos, comp); // Sort the left side of the pivot
|
||||
_quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pointer to the memory location of the first element of `array`.
|
||||
*/
|
||||
function _begin(bytes32[] memory array) private pure returns (uint256 ptr) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
ptr := add(array, 0x20)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
|
||||
* that comes just after the last element of the array.
|
||||
*/
|
||||
function _end(bytes32[] memory array) private pure returns (uint256 ptr) {
|
||||
unchecked {
|
||||
return _begin(array) + array.length * 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load memory word (as a bytes32) at location `ptr`.
|
||||
*/
|
||||
function _mload(uint256 ptr) private pure returns (bytes32 value) {
|
||||
assembly {
|
||||
value := mload(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swaps the elements memory location `ptr1` and `ptr2`.
|
||||
*/
|
||||
function _swap(uint256 ptr1, uint256 ptr2) private pure {
|
||||
assembly {
|
||||
let value1 := mload(ptr1)
|
||||
let value2 := mload(ptr2)
|
||||
mstore(ptr1, value2)
|
||||
mstore(ptr2, value1)
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Comparator for sorting arrays in increasing order.
|
||||
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast address memory array to uint256 memory array
|
||||
function _castToBytes32Array(address[] memory input) private pure returns (bytes32[] memory output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast uint256 memory array to uint256 memory array
|
||||
function _castToBytes32Array(uint256[] memory input) private pure returns (bytes32[] memory output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast address comp function to bytes32 comp function
|
||||
function _castToBytes32Comp(
|
||||
function(address, address) pure returns (bool) input
|
||||
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast uint256 comp function to bytes32 comp function
|
||||
function _castToBytes32Comp(
|
||||
function(uint256, uint256) pure returns (bool) input
|
||||
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Searches a sorted `array` and returns the first index that contains
|
||||
* a value greater or equal to `element`. If no such index exists (i.e. all
|
||||
* values in the array are strictly less than `element`), the array length is
|
||||
* returned. Time complexity O(log n).
|
||||
*
|
||||
* NOTE: The `array` is expected to be sorted in ascending order, and to
|
||||
* contain no repeated elements.
|
||||
*
|
||||
* IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
|
||||
* support for repeated elements in the array. The {lowerBound} function should
|
||||
* be used instead.
|
||||
*/
|
||||
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
|
||||
uint256 low = 0;
|
||||
uint256 high = array.length;
|
||||
|
||||
if (high == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
|
||||
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
|
||||
// because Math.average rounds towards zero (it does integer division with truncation).
|
||||
if (unsafeAccess(array, mid).value > element) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
|
||||
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
|
||||
return low - 1;
|
||||
} else {
|
||||
return low;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Searches an `array` sorted in ascending order and returns the first
|
||||
* index that contains a value greater or equal than `element`. If no such index
|
||||
* exists (i.e. all values in the array are strictly less than `element`), the array
|
||||
* length is returned. Time complexity O(log n).
|
||||
*
|
||||
* See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
|
||||
*/
|
||||
function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
|
||||
uint256 low = 0;
|
||||
uint256 high = array.length;
|
||||
|
||||
if (high == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
|
||||
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
|
||||
// because Math.average rounds towards zero (it does integer division with truncation).
|
||||
if (unsafeAccess(array, mid).value < element) {
|
||||
// this cannot overflow because mid < high
|
||||
unchecked {
|
||||
low = mid + 1;
|
||||
}
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Searches an `array` sorted in ascending order and returns the first
|
||||
* index that contains a value strictly greater than `element`. If no such index
|
||||
* exists (i.e. all values in the array are strictly less than `element`), the array
|
||||
* length is returned. Time complexity O(log n).
|
||||
*
|
||||
* See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
|
||||
*/
|
||||
function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
|
||||
uint256 low = 0;
|
||||
uint256 high = array.length;
|
||||
|
||||
if (high == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
|
||||
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
|
||||
// because Math.average rounds towards zero (it does integer division with truncation).
|
||||
if (unsafeAccess(array, mid).value > element) {
|
||||
high = mid;
|
||||
} else {
|
||||
// this cannot overflow because mid < high
|
||||
unchecked {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {lowerBound}, but with an array in memory.
|
||||
*/
|
||||
function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
|
||||
uint256 low = 0;
|
||||
uint256 high = array.length;
|
||||
|
||||
if (high == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
|
||||
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
|
||||
// because Math.average rounds towards zero (it does integer division with truncation).
|
||||
if (unsafeMemoryAccess(array, mid) < element) {
|
||||
// this cannot overflow because mid < high
|
||||
unchecked {
|
||||
low = mid + 1;
|
||||
}
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {upperBound}, but with an array in memory.
|
||||
*/
|
||||
function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
|
||||
uint256 low = 0;
|
||||
uint256 high = array.length;
|
||||
|
||||
if (high == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
|
||||
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
|
||||
// because Math.average rounds towards zero (it does integer division with truncation).
|
||||
if (unsafeMemoryAccess(array, mid) > element) {
|
||||
high = mid;
|
||||
} else {
|
||||
// this cannot overflow because mid < high
|
||||
unchecked {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
|
||||
bytes32 slot;
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
slot := arr.slot
|
||||
}
|
||||
return slot.deriveArray().offset(pos).getAddressSlot();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
|
||||
bytes32 slot;
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
slot := arr.slot
|
||||
}
|
||||
return slot.deriveArray().offset(pos).getBytes32Slot();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
|
||||
bytes32 slot;
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
slot := arr.slot
|
||||
}
|
||||
return slot.deriveArray().offset(pos).getUint256Slot();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
|
||||
assembly {
|
||||
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
|
||||
assembly {
|
||||
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain `pos` is lower than the array length.
|
||||
*/
|
||||
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
|
||||
assembly {
|
||||
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of an dynamic array. Directly writing to `.length` is forbidden.
|
||||
*
|
||||
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
|
||||
*/
|
||||
function unsafeSetLength(address[] storage array, uint256 len) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of an dynamic array. Directly writing to `.length` is forbidden.
|
||||
*
|
||||
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
|
||||
*/
|
||||
function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of an dynamic array. Directly writing to `.length` is forbidden.
|
||||
*
|
||||
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
|
||||
*/
|
||||
function unsafeSetLength(uint256[] storage array, uint256 len) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
120
lib_openzeppelin_contracts/contracts/utils/Base64.sol
Normal file
120
lib_openzeppelin_contracts/contracts/utils/Base64.sol
Normal file
@@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Provides a set of functions to operate with Base64 strings.
|
||||
*/
|
||||
library Base64 {
|
||||
/**
|
||||
* @dev Base64 Encoding/Decoding Table
|
||||
* See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
|
||||
*/
|
||||
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
/**
|
||||
* @dev Converts a `bytes` to its Bytes64 `string` representation.
|
||||
*/
|
||||
function encode(bytes memory data) internal pure returns (string memory) {
|
||||
return _encode(data, _TABLE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts a `bytes` to its Bytes64Url `string` representation.
|
||||
*/
|
||||
function encodeURL(bytes memory data) internal pure returns (string memory) {
|
||||
return _encode(data, _TABLE_URL, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal table-agnostic conversion
|
||||
*/
|
||||
function _encode(bytes memory data, string memory table, bool withPadding) private pure returns (string memory) {
|
||||
/**
|
||||
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
|
||||
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
|
||||
*/
|
||||
if (data.length == 0) return "";
|
||||
|
||||
// If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then
|
||||
// multiplied by 4 so that it leaves room for padding the last chunk
|
||||
// - `data.length + 2` -> Round up
|
||||
// - `/ 3` -> Number of 3-bytes chunks
|
||||
// - `4 *` -> 4 characters for each chunk
|
||||
// If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as
|
||||
// opposed to when padding is required to fill the last chunk.
|
||||
// - `4 *` -> 4 characters for each chunk
|
||||
// - `data.length + 2` -> Round up
|
||||
// - `/ 3` -> Number of 3-bytes chunks
|
||||
uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;
|
||||
|
||||
string memory result = new string(resultLength);
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
// Prepare the lookup table (skip the first "length" byte)
|
||||
let tablePtr := add(table, 1)
|
||||
|
||||
// Prepare result pointer, jump over length
|
||||
let resultPtr := add(result, 0x20)
|
||||
let dataPtr := data
|
||||
let endPtr := add(data, mload(data))
|
||||
|
||||
// In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
|
||||
// set it to zero to make sure no dirty bytes are read in that section.
|
||||
let afterPtr := add(endPtr, 0x20)
|
||||
let afterCache := mload(afterPtr)
|
||||
mstore(afterPtr, 0x00)
|
||||
|
||||
// Run over the input, 3 bytes at a time
|
||||
for {
|
||||
|
||||
} lt(dataPtr, endPtr) {
|
||||
|
||||
} {
|
||||
// Advance 3 bytes
|
||||
dataPtr := add(dataPtr, 3)
|
||||
let input := mload(dataPtr)
|
||||
|
||||
// To write each character, shift the 3 byte (24 bits) chunk
|
||||
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
|
||||
// and apply logical AND with 0x3F to bitmask the least significant 6 bits.
|
||||
// Use this as an index into the lookup table, mload an entire word
|
||||
// so the desired character is in the least significant byte, and
|
||||
// mstore8 this least significant byte into the result and continue.
|
||||
|
||||
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
|
||||
resultPtr := add(resultPtr, 1) // Advance
|
||||
|
||||
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
|
||||
resultPtr := add(resultPtr, 1) // Advance
|
||||
|
||||
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
|
||||
resultPtr := add(resultPtr, 1) // Advance
|
||||
|
||||
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
|
||||
resultPtr := add(resultPtr, 1) // Advance
|
||||
}
|
||||
|
||||
// Reset the value that was cached
|
||||
mstore(afterPtr, afterCache)
|
||||
|
||||
if withPadding {
|
||||
// When data `bytes` is not exactly 3 bytes long
|
||||
// it is padded with `=` characters at the end
|
||||
switch mod(mload(data), 3)
|
||||
case 1 {
|
||||
mstore8(sub(resultPtr, 1), 0x3d)
|
||||
mstore8(sub(resultPtr, 2), 0x3d)
|
||||
}
|
||||
case 2 {
|
||||
mstore8(sub(resultPtr, 1), 0x3d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
28
lib_openzeppelin_contracts/contracts/utils/Context.sol
Normal file
28
lib_openzeppelin_contracts/contracts/utils/Context.sol
Normal file
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Provides information about the current execution context, including the
|
||||
* sender of the transaction and its data. While these are generally available
|
||||
* via msg.sender and msg.data, they should not be accessed in such a direct
|
||||
* manner, since when dealing with meta-transactions the account sending and
|
||||
* paying for execution may not be the actual sender (as far as an application
|
||||
* is concerned).
|
||||
*
|
||||
* This contract is only required for intermediate, library-like contracts.
|
||||
*/
|
||||
abstract contract Context {
|
||||
function _msgSender() internal view virtual returns (address) {
|
||||
return msg.sender;
|
||||
}
|
||||
|
||||
function _msgData() internal view virtual returns (bytes calldata) {
|
||||
return msg.data;
|
||||
}
|
||||
|
||||
function _contextSuffixLength() internal view virtual returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
88
lib_openzeppelin_contracts/contracts/utils/Create2.sol
Normal file
88
lib_openzeppelin_contracts/contracts/utils/Create2.sol
Normal file
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Errors} from "./Errors.sol";
|
||||
|
||||
/**
|
||||
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
|
||||
* `CREATE2` can be used to compute in advance the address where a smart
|
||||
* contract will be deployed, which allows for interesting new mechanisms known
|
||||
* as 'counterfactual interactions'.
|
||||
*
|
||||
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
|
||||
* information.
|
||||
*/
|
||||
library Create2 {
|
||||
/**
|
||||
* @dev There's no code to deploy.
|
||||
*/
|
||||
error Create2EmptyBytecode();
|
||||
|
||||
/**
|
||||
* @dev Deploys a contract using `CREATE2`. The address where the contract
|
||||
* will be deployed can be known in advance via {computeAddress}.
|
||||
*
|
||||
* The bytecode for a contract can be obtained from Solidity with
|
||||
* `type(contractName).creationCode`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `bytecode` must not be empty.
|
||||
* - `salt` must have not been used for `bytecode` already.
|
||||
* - the factory must have a balance of at least `amount`.
|
||||
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
|
||||
*/
|
||||
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
|
||||
if (address(this).balance < amount) {
|
||||
revert Errors.InsufficientBalance(address(this).balance, amount);
|
||||
}
|
||||
if (bytecode.length == 0) {
|
||||
revert Create2EmptyBytecode();
|
||||
}
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
|
||||
}
|
||||
if (addr == address(0)) {
|
||||
revert Errors.FailedDeployment();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
|
||||
* `bytecodeHash` or `salt` will result in a new destination address.
|
||||
*/
|
||||
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
|
||||
return computeAddress(salt, bytecodeHash, address(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
|
||||
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
|
||||
*/
|
||||
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let ptr := mload(0x40) // Get free memory pointer
|
||||
|
||||
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
|
||||
// |-------------------|---------------------------------------------------------------------------|
|
||||
// | bytecodeHash | CCCCCCCCCCCCC...CC |
|
||||
// | salt | BBBBBBBBBBBBB...BB |
|
||||
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
|
||||
// | 0xFF | FF |
|
||||
// |-------------------|---------------------------------------------------------------------------|
|
||||
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
|
||||
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
|
||||
|
||||
mstore(add(ptr, 0x40), bytecodeHash)
|
||||
mstore(add(ptr, 0x20), salt)
|
||||
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
|
||||
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
|
||||
mstore8(start, 0xff)
|
||||
addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
|
||||
}
|
||||
}
|
||||
}
|
||||
26
lib_openzeppelin_contracts/contracts/utils/Errors.sol
Normal file
26
lib_openzeppelin_contracts/contracts/utils/Errors.sol
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Collection of common custom errors used in multiple contracts
|
||||
*
|
||||
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
|
||||
* It is recommended to avoid relying on the error API for critical functionality.
|
||||
*/
|
||||
library Errors {
|
||||
/**
|
||||
* @dev The ETH balance of the account is not enough to perform the operation.
|
||||
*/
|
||||
error InsufficientBalance(uint256 balance, uint256 needed);
|
||||
|
||||
/**
|
||||
* @dev A call to an address target failed. The target may have reverted.
|
||||
*/
|
||||
error FailedCall();
|
||||
|
||||
/**
|
||||
* @dev The deployment failed.
|
||||
*/
|
||||
error FailedDeployment();
|
||||
}
|
||||
37
lib_openzeppelin_contracts/contracts/utils/Multicall.sol
Normal file
37
lib_openzeppelin_contracts/contracts/utils/Multicall.sol
Normal file
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Multicall.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Address} from "./Address.sol";
|
||||
import {Context} from "./Context.sol";
|
||||
|
||||
/**
|
||||
* @dev Provides a function to batch together multiple calls in a single external call.
|
||||
*
|
||||
* Consider any assumption about calldata validation performed by the sender may be violated if it's not especially
|
||||
* careful about sending transactions invoking {multicall}. For example, a relay address that filters function
|
||||
* selectors won't filter calls nested within a {multicall} operation.
|
||||
*
|
||||
* NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).
|
||||
* If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data`
|
||||
* to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of
|
||||
* {_msgSender} are not propagated to subcalls.
|
||||
*/
|
||||
abstract contract Multicall is Context {
|
||||
/**
|
||||
* @dev Receives and executes a batch of function calls on this contract.
|
||||
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
|
||||
*/
|
||||
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
|
||||
bytes memory context = msg.sender == _msgSender()
|
||||
? new bytes(0)
|
||||
: msg.data[msg.data.length - _contextSuffixLength():];
|
||||
|
||||
results = new bytes[](data.length);
|
||||
for (uint256 i = 0; i < data.length; i++) {
|
||||
results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
46
lib_openzeppelin_contracts/contracts/utils/Nonces.sol
Normal file
46
lib_openzeppelin_contracts/contracts/utils/Nonces.sol
Normal file
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Provides tracking nonces for addresses. Nonces will only increment.
|
||||
*/
|
||||
abstract contract Nonces {
|
||||
/**
|
||||
* @dev The nonce used for an `account` is not the expected current nonce.
|
||||
*/
|
||||
error InvalidAccountNonce(address account, uint256 currentNonce);
|
||||
|
||||
mapping(address account => uint256) private _nonces;
|
||||
|
||||
/**
|
||||
* @dev Returns the next unused nonce for an address.
|
||||
*/
|
||||
function nonces(address owner) public view virtual returns (uint256) {
|
||||
return _nonces[owner];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Consumes a nonce.
|
||||
*
|
||||
* Returns the current value and increments nonce.
|
||||
*/
|
||||
function _useNonce(address owner) internal virtual returns (uint256) {
|
||||
// For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
|
||||
// decremented or reset. This guarantees that the nonce never overflows.
|
||||
unchecked {
|
||||
// It is important to do x++ and not ++x here.
|
||||
return _nonces[owner]++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
|
||||
*/
|
||||
function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
|
||||
uint256 current = _useNonce(owner);
|
||||
if (nonce != current) {
|
||||
revert InvalidAccountNonce(owner, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
lib_openzeppelin_contracts/contracts/utils/Packing.sol
Normal file
40
lib_openzeppelin_contracts/contracts/utils/Packing.sol
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Helper library packing and unpacking multiple values into bytes32
|
||||
*/
|
||||
library Packing {
|
||||
type Uint128x2 is bytes32;
|
||||
|
||||
/// @dev Cast a bytes32 into a Uint128x2
|
||||
function asUint128x2(bytes32 self) internal pure returns (Uint128x2) {
|
||||
return Uint128x2.wrap(self);
|
||||
}
|
||||
|
||||
/// @dev Cast a Uint128x2 into a bytes32
|
||||
function asBytes32(Uint128x2 self) internal pure returns (bytes32) {
|
||||
return Uint128x2.unwrap(self);
|
||||
}
|
||||
|
||||
/// @dev Pack two uint128 into a Uint128x2
|
||||
function pack(uint128 first128, uint128 second128) internal pure returns (Uint128x2) {
|
||||
return Uint128x2.wrap(bytes32(bytes16(first128)) | bytes32(uint256(second128)));
|
||||
}
|
||||
|
||||
/// @dev Split a Uint128x2 into two uint128
|
||||
function split(Uint128x2 self) internal pure returns (uint128, uint128) {
|
||||
return (first(self), second(self));
|
||||
}
|
||||
|
||||
/// @dev Get the first element of a Uint128x2 counting from higher to lower bytes
|
||||
function first(Uint128x2 self) internal pure returns (uint128) {
|
||||
return uint128(bytes16(Uint128x2.unwrap(self)));
|
||||
}
|
||||
|
||||
/// @dev Get the second element of a Uint128x2 counting from higher to lower bytes
|
||||
function second(Uint128x2 self) internal pure returns (uint128) {
|
||||
return uint128(uint256(Uint128x2.unwrap(self)));
|
||||
}
|
||||
}
|
||||
55
lib_openzeppelin_contracts/contracts/utils/Panic.sol
Normal file
55
lib_openzeppelin_contracts/contracts/utils/Panic.sol
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Helper library for emitting standardized panic codes.
|
||||
*
|
||||
* ```solidity
|
||||
* contract Example {
|
||||
* using Panic for uint256;
|
||||
*
|
||||
* // Use any of the declared internal constants
|
||||
* function foo() { Panic.GENERIC.panic(); }
|
||||
*
|
||||
* // Alternatively
|
||||
* function foo() { Panic.panic(Panic.GENERIC); }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
|
||||
*/
|
||||
// slither-disable-next-line unused-state
|
||||
library Panic {
|
||||
/// @dev generic / unspecified error
|
||||
uint256 internal constant GENERIC = 0x00;
|
||||
/// @dev used by the assert() builtin
|
||||
uint256 internal constant ASSERT = 0x01;
|
||||
/// @dev arithmetic underflow or overflow
|
||||
uint256 internal constant UNDER_OVERFLOW = 0x11;
|
||||
/// @dev division or modulo by zero
|
||||
uint256 internal constant DIVISION_BY_ZERO = 0x12;
|
||||
/// @dev enum conversion error
|
||||
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
|
||||
/// @dev invalid encoding in storage
|
||||
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
|
||||
/// @dev empty array pop
|
||||
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
|
||||
/// @dev array out of bounds access
|
||||
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
|
||||
/// @dev resource error (too large allocation or too large array)
|
||||
uint256 internal constant RESOURCE_ERROR = 0x41;
|
||||
/// @dev calling invalid internal function
|
||||
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
|
||||
|
||||
/// @dev Reverts with a panic code. Recommended to use with
|
||||
/// the internal constants with predefined codes.
|
||||
function panic(uint256 code) internal pure {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, 0x4e487b71)
|
||||
mstore(0x20, code)
|
||||
revert(0x1c, 0x24)
|
||||
}
|
||||
}
|
||||
}
|
||||
119
lib_openzeppelin_contracts/contracts/utils/Pausable.sol
Normal file
119
lib_openzeppelin_contracts/contracts/utils/Pausable.sol
Normal file
@@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Context} from "../utils/Context.sol";
|
||||
|
||||
/**
|
||||
* @dev Contract module which allows children to implement an emergency stop
|
||||
* mechanism that can be triggered by an authorized account.
|
||||
*
|
||||
* This module is used through inheritance. It will make available the
|
||||
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
|
||||
* the functions of your contract. Note that they will not be pausable by
|
||||
* simply including this module, only once the modifiers are put in place.
|
||||
*/
|
||||
abstract contract Pausable is Context {
|
||||
bool private _paused;
|
||||
|
||||
/**
|
||||
* @dev Emitted when the pause is triggered by `account`.
|
||||
*/
|
||||
event Paused(address account);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the pause is lifted by `account`.
|
||||
*/
|
||||
event Unpaused(address account);
|
||||
|
||||
/**
|
||||
* @dev The operation failed because the contract is paused.
|
||||
*/
|
||||
error EnforcedPause();
|
||||
|
||||
/**
|
||||
* @dev The operation failed because the contract is not paused.
|
||||
*/
|
||||
error ExpectedPause();
|
||||
|
||||
/**
|
||||
* @dev Initializes the contract in unpaused state.
|
||||
*/
|
||||
constructor() {
|
||||
_paused = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is not paused.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must not be paused.
|
||||
*/
|
||||
modifier whenNotPaused() {
|
||||
_requireNotPaused();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is paused.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must be paused.
|
||||
*/
|
||||
modifier whenPaused() {
|
||||
_requirePaused();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the contract is paused, and false otherwise.
|
||||
*/
|
||||
function paused() public view virtual returns (bool) {
|
||||
return _paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Throws if the contract is paused.
|
||||
*/
|
||||
function _requireNotPaused() internal view virtual {
|
||||
if (paused()) {
|
||||
revert EnforcedPause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Throws if the contract is not paused.
|
||||
*/
|
||||
function _requirePaused() internal view virtual {
|
||||
if (!paused()) {
|
||||
revert ExpectedPause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Triggers stopped state.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must not be paused.
|
||||
*/
|
||||
function _pause() internal virtual whenNotPaused {
|
||||
_paused = true;
|
||||
emit Paused(_msgSender());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns to normal state.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must be paused.
|
||||
*/
|
||||
function _unpause() internal virtual whenPaused {
|
||||
_paused = false;
|
||||
emit Unpaused(_msgSender());
|
||||
}
|
||||
}
|
||||
129
lib_openzeppelin_contracts/contracts/utils/README.adoc
Normal file
129
lib_openzeppelin_contracts/contracts/utils/README.adoc
Normal file
@@ -0,0 +1,129 @@
|
||||
= Utilities
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils
|
||||
|
||||
Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives.
|
||||
|
||||
* {Math}, {SignedMath}: Implementation of various arithmetic functions.
|
||||
* {SafeCast}: Checked downcasting functions to avoid silent truncation.
|
||||
* {ECDSA}, {MessageHashUtils}: Libraries for interacting with ECDSA signatures.
|
||||
* {SignatureChecker}: A library helper to support regular ECDSA from EOAs as well as ERC-1271 signatures for smart contracts.
|
||||
* {Hashes}: Commonly used hash functions.
|
||||
* {MerkleProof}: Functions for verifying https://en.wikipedia.org/wiki/Merkle_tree[Merkle Tree] proofs.
|
||||
* {EIP712}: Contract with functions to allow processing signed typed structure data according to https://eips.ethereum.org/EIPS/eip-712[EIP-712].
|
||||
* {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions.
|
||||
* {ReentrancyGuardTransient}: Variant of {ReentrancyGuard} that uses transient storage (https://eips.ethereum.org/EIPS/eip-1153[EIP-1153]).
|
||||
* {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending.
|
||||
* {Nonces}: Utility for tracking and verifying address nonces that only increment.
|
||||
* {ERC165, ERC165Checker}: Utilities for inspecting interfaces supported by contracts.
|
||||
* {BitMaps}: A simple library to manage boolean value mapped to a numerical index in an efficient way.
|
||||
* {EnumerableMap}: A type like Solidity's https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`], but with key-value _enumeration_: this will let you know how many entries a mapping has, and iterate over them (which is not possible with `mapping`).
|
||||
* {EnumerableSet}: Like {EnumerableMap}, but for https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets]. Can be used to store privileged accounts, issued IDs, etc.
|
||||
* {DoubleEndedQueue}: An implementation of a https://en.wikipedia.org/wiki/Double-ended_queue[double ended queue] whose values can be removed added or remove from both sides. Useful for FIFO and LIFO structures.
|
||||
* {CircularBuffer}: A data structure to store the last N values pushed to it.
|
||||
* {Checkpoints}: A data structure to store values mapped to an strictly increasing key. Can be used for storing and accessing values over time.
|
||||
* {MerkleTree}: A library with https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures and helper functions.
|
||||
* {Create2}: Wrapper around the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode] for safe use without having to deal with low-level assembly.
|
||||
* {Address}: Collection of functions for overloading Solidity's https://docs.soliditylang.org/en/latest/types.html#address[`address`] type.
|
||||
* {Arrays}: Collection of functions that operate on https://docs.soliditylang.org/en/latest/types.html#arrays[`arrays`].
|
||||
* {Base64}: On-chain base64 and base64URL encoding according to https://datatracker.ietf.org/doc/html/rfc4648[RFC-4648].
|
||||
* {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).
|
||||
* {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.
|
||||
* {Context}: An utility for abstracting the sender and calldata in the current execution context.
|
||||
* {Packing}: A library for packing and unpacking multiple values into bytes32
|
||||
* {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].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Because Solidity does not support generic types, {EnumerableMap} and {EnumerableSet} are specialized to a limited number of key-value types.
|
||||
====
|
||||
|
||||
== Math
|
||||
|
||||
{{Math}}
|
||||
|
||||
{{SignedMath}}
|
||||
|
||||
{{SafeCast}}
|
||||
|
||||
== Cryptography
|
||||
|
||||
{{ECDSA}}
|
||||
|
||||
{{EIP712}}
|
||||
|
||||
{{MessageHashUtils}}
|
||||
|
||||
{{SignatureChecker}}
|
||||
|
||||
{{Hashes}}
|
||||
|
||||
{{MerkleProof}}
|
||||
|
||||
== Security
|
||||
|
||||
{{ReentrancyGuard}}
|
||||
|
||||
{{ReentrancyGuardTransient}}
|
||||
|
||||
{{Pausable}}
|
||||
|
||||
{{Nonces}}
|
||||
|
||||
== Introspection
|
||||
|
||||
This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_.
|
||||
|
||||
Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. ERC-20 tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors.
|
||||
|
||||
{{IERC165}}
|
||||
|
||||
{{ERC165}}
|
||||
|
||||
{{ERC165Checker}}
|
||||
|
||||
== Data Structures
|
||||
|
||||
{{BitMaps}}
|
||||
|
||||
{{EnumerableMap}}
|
||||
|
||||
{{EnumerableSet}}
|
||||
|
||||
{{DoubleEndedQueue}}
|
||||
|
||||
{{CircularBuffer}}
|
||||
|
||||
{{Checkpoints}}
|
||||
|
||||
{{MerkleTree}}
|
||||
|
||||
== Libraries
|
||||
|
||||
{{Create2}}
|
||||
|
||||
{{Address}}
|
||||
|
||||
{{Arrays}}
|
||||
|
||||
{{Base64}}
|
||||
|
||||
{{Strings}}
|
||||
|
||||
{{ShortStrings}}
|
||||
|
||||
{{SlotDerivation}}
|
||||
|
||||
{{StorageSlot}}
|
||||
|
||||
{{Multicall}}
|
||||
|
||||
{{Context}}
|
||||
|
||||
{{Packing}}
|
||||
|
||||
{{Panic}}
|
||||
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Contract module that helps prevent reentrant calls to a function.
|
||||
*
|
||||
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
|
||||
* available, which can be applied to functions to make sure there are no nested
|
||||
* (reentrant) calls to them.
|
||||
*
|
||||
* Note that because there is a single `nonReentrant` guard, functions marked as
|
||||
* `nonReentrant` may not call one another. This can be worked around by making
|
||||
* those functions `private`, and then adding `external` `nonReentrant` entry
|
||||
* points to them.
|
||||
*
|
||||
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
|
||||
* consider using {ReentrancyGuardTransient} instead.
|
||||
*
|
||||
* TIP: If you would like to learn more about reentrancy and alternative ways
|
||||
* to protect against it, check out our blog post
|
||||
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
|
||||
*/
|
||||
abstract contract ReentrancyGuard {
|
||||
// Booleans are more expensive than uint256 or any type that takes up a full
|
||||
// word because each write operation emits an extra SLOAD to first read the
|
||||
// slot's contents, replace the bits taken up by the boolean, and then write
|
||||
// back. This is the compiler's defense against contract upgrades and
|
||||
// pointer aliasing, and it cannot be disabled.
|
||||
|
||||
// The values being non-zero value makes deployment a bit more expensive,
|
||||
// but in exchange the refund on every call to nonReentrant will be lower in
|
||||
// amount. Since refunds are capped to a percentage of the total
|
||||
// transaction's gas, it is best to keep them low in cases like this one, to
|
||||
// increase the likelihood of the full refund coming into effect.
|
||||
uint256 private constant NOT_ENTERED = 1;
|
||||
uint256 private constant ENTERED = 2;
|
||||
|
||||
uint256 private _status;
|
||||
|
||||
/**
|
||||
* @dev Unauthorized reentrant call.
|
||||
*/
|
||||
error ReentrancyGuardReentrantCall();
|
||||
|
||||
constructor() {
|
||||
_status = NOT_ENTERED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
|
||||
function _nonReentrantBefore() private {
|
||||
// On the first call to nonReentrant, _status will be NOT_ENTERED
|
||||
if (_status == ENTERED) {
|
||||
revert ReentrancyGuardReentrantCall();
|
||||
}
|
||||
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_status = ENTERED;
|
||||
}
|
||||
|
||||
function _nonReentrantAfter() private {
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_status = NOT_ENTERED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 _status == ENTERED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {StorageSlot} from "./StorageSlot.sol";
|
||||
|
||||
/**
|
||||
* @dev Variant of {ReentrancyGuard} that uses transient storage.
|
||||
*
|
||||
* NOTE: This variant only works on networks where EIP-1153 is available.
|
||||
*/
|
||||
abstract contract ReentrancyGuardTransient {
|
||||
using StorageSlot 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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
123
lib_openzeppelin_contracts/contracts/utils/ShortStrings.sol
Normal file
123
lib_openzeppelin_contracts/contracts/utils/ShortStrings.sol
Normal file
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {StorageSlot} from "./StorageSlot.sol";
|
||||
|
||||
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
|
||||
// | length | 0x BB |
|
||||
type ShortString is bytes32;
|
||||
|
||||
/**
|
||||
* @dev This library provides functions to convert short memory strings
|
||||
* into a `ShortString` type that can be used as an immutable variable.
|
||||
*
|
||||
* Strings of arbitrary length can be optimized using this library if
|
||||
* they are short enough (up to 31 bytes) by packing them with their
|
||||
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
|
||||
* fallback mechanism can be used for every other case.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```solidity
|
||||
* contract Named {
|
||||
* using ShortStrings for *;
|
||||
*
|
||||
* ShortString private immutable _name;
|
||||
* string private _nameFallback;
|
||||
*
|
||||
* constructor(string memory contractName) {
|
||||
* _name = contractName.toShortStringWithFallback(_nameFallback);
|
||||
* }
|
||||
*
|
||||
* function name() external view returns (string memory) {
|
||||
* return _name.toStringWithFallback(_nameFallback);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
library ShortStrings {
|
||||
// Used as an identifier for strings longer than 31 bytes.
|
||||
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
|
||||
|
||||
error StringTooLong(string str);
|
||||
error InvalidShortString();
|
||||
|
||||
/**
|
||||
* @dev Encode a string of at most 31 chars into a `ShortString`.
|
||||
*
|
||||
* This will trigger a `StringTooLong` error is the input string is too long.
|
||||
*/
|
||||
function toShortString(string memory str) internal pure returns (ShortString) {
|
||||
bytes memory bstr = bytes(str);
|
||||
if (bstr.length > 31) {
|
||||
revert StringTooLong(str);
|
||||
}
|
||||
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decode a `ShortString` back to a "normal" string.
|
||||
*/
|
||||
function toString(ShortString sstr) internal pure returns (string memory) {
|
||||
uint256 len = byteLength(sstr);
|
||||
// using `new string(len)` would work locally but is not memory safe.
|
||||
string memory str = new string(32);
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(str, len)
|
||||
mstore(add(str, 0x20), sstr)
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the length of a `ShortString`.
|
||||
*/
|
||||
function byteLength(ShortString sstr) internal pure returns (uint256) {
|
||||
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
|
||||
if (result > 31) {
|
||||
revert InvalidShortString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
|
||||
*/
|
||||
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
|
||||
if (bytes(value).length < 32) {
|
||||
return toShortString(value);
|
||||
} else {
|
||||
StorageSlot.getStringSlot(store).value = value;
|
||||
return ShortString.wrap(FALLBACK_SENTINEL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
|
||||
*/
|
||||
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
|
||||
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
|
||||
return toString(value);
|
||||
} else {
|
||||
return store;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
|
||||
* {setWithFallback}.
|
||||
*
|
||||
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
|
||||
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
|
||||
*/
|
||||
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
|
||||
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
|
||||
return byteLength(value);
|
||||
} else {
|
||||
return bytes(store).length;
|
||||
}
|
||||
}
|
||||
}
|
||||
161
lib_openzeppelin_contracts/contracts/utils/SlotDerivation.sol
Normal file
161
lib_openzeppelin_contracts/contracts/utils/SlotDerivation.sol
Normal file
@@ -0,0 +1,161 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
|
||||
* corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
|
||||
* the solidity language / compiler.
|
||||
*
|
||||
* See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
|
||||
*
|
||||
* Example usage:
|
||||
* ```solidity
|
||||
* contract Example {
|
||||
* // Add the library methods
|
||||
* using StorageSlot for bytes32;
|
||||
* using SlotDerivation for bytes32;
|
||||
*
|
||||
* // Declare a namespace
|
||||
* string private constant _NAMESPACE = "<namespace>" // eg. OpenZeppelin.Slot
|
||||
*
|
||||
* function setValueInNamespace(uint256 key, address newValue) internal {
|
||||
* _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
|
||||
* }
|
||||
*
|
||||
* function getValueInNamespace(uint256 key) internal view returns (address) {
|
||||
* return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* TIP: Consider using this library along with {StorageSlot}.
|
||||
*
|
||||
* NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
|
||||
* upgrade safety will ignore the slots accessed through this library.
|
||||
*/
|
||||
library SlotDerivation {
|
||||
/**
|
||||
* @dev Derive an ERC-7201 slot from a string (namespace).
|
||||
*/
|
||||
function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
|
||||
slot := and(keccak256(0x00, 0x20), not(0xff))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add an offset to a slot to get the n-th element of a structure or an array.
|
||||
*/
|
||||
function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
|
||||
unchecked {
|
||||
return bytes32(uint256(slot) + pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of the first element in an array from the slot where the length is stored.
|
||||
*/
|
||||
function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, slot)
|
||||
result := keccak256(0x00, 0x20)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, key)
|
||||
mstore(0x20, slot)
|
||||
result := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, key)
|
||||
mstore(0x20, slot)
|
||||
result := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, key)
|
||||
mstore(0x20, slot)
|
||||
result := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, key)
|
||||
mstore(0x20, slot)
|
||||
result := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, key)
|
||||
mstore(0x20, slot)
|
||||
result := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let length := mload(key)
|
||||
let begin := add(key, 0x20)
|
||||
let end := add(begin, length)
|
||||
let cache := mload(end)
|
||||
mstore(end, slot)
|
||||
result := keccak256(begin, add(length, 0x20))
|
||||
mstore(end, cache)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Derive the location of a mapping element from the key.
|
||||
*/
|
||||
function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let length := mload(key)
|
||||
let begin := add(key, 0x20)
|
||||
let end := add(begin, length)
|
||||
let cache := mload(end)
|
||||
mstore(end, slot)
|
||||
result := keccak256(begin, add(length, 0x20))
|
||||
mstore(end, cache)
|
||||
}
|
||||
}
|
||||
}
|
||||
330
lib_openzeppelin_contracts/contracts/utils/StorageSlot.sol
Normal file
330
lib_openzeppelin_contracts/contracts/utils/StorageSlot.sol
Normal file
@@ -0,0 +1,330 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* @dev Library for reading and writing primitive types to specific storage slots.
|
||||
*
|
||||
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
|
||||
* This library helps with reading and writing to such slots without the need for inline assembly.
|
||||
*
|
||||
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
|
||||
*
|
||||
* Example usage to set ERC-1967 implementation slot:
|
||||
* ```solidity
|
||||
* contract ERC1967 {
|
||||
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
|
||||
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
|
||||
*
|
||||
* function _getImplementation() internal view returns (address) {
|
||||
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
|
||||
* }
|
||||
*
|
||||
* function _setImplementation(address newImplementation) internal {
|
||||
* require(newImplementation.code.length > 0);
|
||||
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 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 {
|
||||
struct AddressSlot {
|
||||
address value;
|
||||
}
|
||||
|
||||
struct BooleanSlot {
|
||||
bool value;
|
||||
}
|
||||
|
||||
struct Bytes32Slot {
|
||||
bytes32 value;
|
||||
}
|
||||
|
||||
struct Uint256Slot {
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct Int256Slot {
|
||||
int256 value;
|
||||
}
|
||||
|
||||
struct StringSlot {
|
||||
string value;
|
||||
}
|
||||
|
||||
struct BytesSlot {
|
||||
bytes value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `Int256Slot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `StringSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
|
||||
*/
|
||||
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := store.slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
|
||||
*/
|
||||
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
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) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(AddressSlotType slot, address value) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(BooleanSlotType slot) internal view returns (bool value) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(BooleanSlotType slot, bool value) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(Bytes32SlotType slot) internal view returns (bytes32 value) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(Bytes32SlotType slot, bytes32 value) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(Uint256SlotType slot) internal view returns (uint256 value) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(Uint256SlotType slot, uint256 value) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(Int256SlotType slot) internal view returns (int256 value) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(Int256SlotType slot, int256 value) internal {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
94
lib_openzeppelin_contracts/contracts/utils/Strings.sol
Normal file
94
lib_openzeppelin_contracts/contracts/utils/Strings.sol
Normal file
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "./math/Math.sol";
|
||||
import {SignedMath} from "./math/SignedMath.sol";
|
||||
|
||||
/**
|
||||
* @dev String operations.
|
||||
*/
|
||||
library Strings {
|
||||
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
|
||||
uint8 private constant ADDRESS_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* @dev The `value` string doesn't fit in the specified `length`.
|
||||
*/
|
||||
error StringsInsufficientHexLength(uint256 value, uint256 length);
|
||||
|
||||
/**
|
||||
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
|
||||
*/
|
||||
function toString(uint256 value) internal pure returns (string memory) {
|
||||
unchecked {
|
||||
uint256 length = Math.log10(value) + 1;
|
||||
string memory buffer = new string(length);
|
||||
uint256 ptr;
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
ptr := add(buffer, add(32, length))
|
||||
}
|
||||
while (true) {
|
||||
ptr--;
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
|
||||
}
|
||||
value /= 10;
|
||||
if (value == 0) break;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts a `int256` to its ASCII `string` decimal representation.
|
||||
*/
|
||||
function toStringSigned(int256 value) internal pure returns (string memory) {
|
||||
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
|
||||
*/
|
||||
function toHexString(uint256 value) internal pure returns (string memory) {
|
||||
unchecked {
|
||||
return toHexString(value, Math.log256(value) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
|
||||
*/
|
||||
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
|
||||
uint256 localValue = value;
|
||||
bytes memory buffer = new bytes(2 * length + 2);
|
||||
buffer[0] = "0";
|
||||
buffer[1] = "x";
|
||||
for (uint256 i = 2 * length + 1; i > 1; --i) {
|
||||
buffer[i] = HEX_DIGITS[localValue & 0xf];
|
||||
localValue >>= 4;
|
||||
}
|
||||
if (localValue != 0) {
|
||||
revert StringsInsufficientHexLength(value, length);
|
||||
}
|
||||
return string(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
|
||||
* representation.
|
||||
*/
|
||||
function toHexString(address addr) internal pure returns (string memory) {
|
||||
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the two strings are equal.
|
||||
*/
|
||||
function equal(string memory a, string memory b) internal pure returns (bool) {
|
||||
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
|
||||
*
|
||||
* These functions can be used to verify that a message was signed by the holder
|
||||
* of the private keys of a given address.
|
||||
*/
|
||||
library ECDSA {
|
||||
enum RecoverError {
|
||||
NoError,
|
||||
InvalidSignature,
|
||||
InvalidSignatureLength,
|
||||
InvalidSignatureS
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev The signature derives the `address(0)`.
|
||||
*/
|
||||
error ECDSAInvalidSignature();
|
||||
|
||||
/**
|
||||
* @dev The signature has an invalid length.
|
||||
*/
|
||||
error ECDSAInvalidSignatureLength(uint256 length);
|
||||
|
||||
/**
|
||||
* @dev The signature has an S value that is in the upper half order.
|
||||
*/
|
||||
error ECDSAInvalidSignatureS(bytes32 s);
|
||||
|
||||
/**
|
||||
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
|
||||
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
|
||||
* and a bytes32 providing additional information about the error.
|
||||
*
|
||||
* If no error is returned, then the address can be used for verification purposes.
|
||||
*
|
||||
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
|
||||
* this function rejects them by requiring the `s` value to be in the lower
|
||||
* half order, and the `v` value to be either 27 or 28.
|
||||
*
|
||||
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
|
||||
* verification to be secure: it is possible to craft signatures that
|
||||
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
|
||||
* this is by receiving a hash of the original message (which may otherwise
|
||||
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
|
||||
*
|
||||
* Documentation for signature generation:
|
||||
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
|
||||
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
|
||||
*/
|
||||
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
|
||||
if (signature.length == 65) {
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
uint8 v;
|
||||
// ecrecover takes the signature parameters, and the only way to get them
|
||||
// currently is to use assembly.
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
r := mload(add(signature, 0x20))
|
||||
s := mload(add(signature, 0x40))
|
||||
v := byte(0, mload(add(signature, 0x60)))
|
||||
}
|
||||
return tryRecover(hash, v, r, s);
|
||||
} else {
|
||||
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address that signed a hashed message (`hash`) with
|
||||
* `signature`. This address can then be used for verification purposes.
|
||||
*
|
||||
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
|
||||
* this function rejects them by requiring the `s` value to be in the lower
|
||||
* half order, and the `v` value to be either 27 or 28.
|
||||
*
|
||||
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
|
||||
* verification to be secure: it is possible to craft signatures that
|
||||
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
|
||||
* this is by receiving a hash of the original message (which may otherwise
|
||||
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
|
||||
*/
|
||||
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
|
||||
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
|
||||
_throwError(error, errorArg);
|
||||
return recovered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
|
||||
*
|
||||
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
|
||||
*/
|
||||
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
|
||||
unchecked {
|
||||
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
|
||||
// We do not check for an overflow here since the shift operation results in 0 or 1.
|
||||
uint8 v = uint8((uint256(vs) >> 255) + 27);
|
||||
return tryRecover(hash, v, r, s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
|
||||
*/
|
||||
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
|
||||
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
|
||||
_throwError(error, errorArg);
|
||||
return recovered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
|
||||
* `r` and `s` signature fields separately.
|
||||
*/
|
||||
function tryRecover(
|
||||
bytes32 hash,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) internal pure returns (address, RecoverError, bytes32) {
|
||||
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
|
||||
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
|
||||
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
|
||||
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
|
||||
//
|
||||
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
|
||||
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
|
||||
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
|
||||
// these malleable signatures as well.
|
||||
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
|
||||
return (address(0), RecoverError.InvalidSignatureS, s);
|
||||
}
|
||||
|
||||
// If the signature is valid (and not malleable), return the signer address
|
||||
address signer = ecrecover(hash, v, r, s);
|
||||
if (signer == address(0)) {
|
||||
return (address(0), RecoverError.InvalidSignature, bytes32(0));
|
||||
}
|
||||
|
||||
return (signer, RecoverError.NoError, bytes32(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Overload of {ECDSA-recover} that receives the `v`,
|
||||
* `r` and `s` signature fields separately.
|
||||
*/
|
||||
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
|
||||
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
|
||||
_throwError(error, errorArg);
|
||||
return recovered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
|
||||
*/
|
||||
function _throwError(RecoverError error, bytes32 errorArg) private pure {
|
||||
if (error == RecoverError.NoError) {
|
||||
return; // no error: do nothing
|
||||
} else if (error == RecoverError.InvalidSignature) {
|
||||
revert ECDSAInvalidSignature();
|
||||
} else if (error == RecoverError.InvalidSignatureLength) {
|
||||
revert ECDSAInvalidSignatureLength(uint256(errorArg));
|
||||
} else if (error == RecoverError.InvalidSignatureS) {
|
||||
revert ECDSAInvalidSignatureS(errorArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {MessageHashUtils} from "./MessageHashUtils.sol";
|
||||
import {ShortStrings, ShortString} from "../ShortStrings.sol";
|
||||
import {IERC5267} from "../../interfaces/IERC5267.sol";
|
||||
|
||||
/**
|
||||
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.
|
||||
*
|
||||
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
|
||||
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
|
||||
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
|
||||
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
|
||||
*
|
||||
* This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
|
||||
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
|
||||
* ({_hashTypedDataV4}).
|
||||
*
|
||||
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
|
||||
* the chain id to protect against replay attacks on an eventual fork of the chain.
|
||||
*
|
||||
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
|
||||
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
|
||||
*
|
||||
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
|
||||
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
|
||||
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
|
||||
*
|
||||
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
||||
*/
|
||||
abstract contract EIP712 is IERC5267 {
|
||||
using ShortStrings for *;
|
||||
|
||||
bytes32 private constant TYPE_HASH =
|
||||
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
|
||||
|
||||
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
|
||||
// invalidate the cached domain separator if the chain id changes.
|
||||
bytes32 private immutable _cachedDomainSeparator;
|
||||
uint256 private immutable _cachedChainId;
|
||||
address private immutable _cachedThis;
|
||||
|
||||
bytes32 private immutable _hashedName;
|
||||
bytes32 private immutable _hashedVersion;
|
||||
|
||||
ShortString private immutable _name;
|
||||
ShortString private immutable _version;
|
||||
string private _nameFallback;
|
||||
string private _versionFallback;
|
||||
|
||||
/**
|
||||
* @dev Initializes the domain separator and parameter caches.
|
||||
*
|
||||
* The meaning of `name` and `version` is specified in
|
||||
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:
|
||||
*
|
||||
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
|
||||
* - `version`: the current major version of the signing domain.
|
||||
*
|
||||
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
|
||||
* contract upgrade].
|
||||
*/
|
||||
constructor(string memory name, string memory version) {
|
||||
_name = name.toShortStringWithFallback(_nameFallback);
|
||||
_version = version.toShortStringWithFallback(_versionFallback);
|
||||
_hashedName = keccak256(bytes(name));
|
||||
_hashedVersion = keccak256(bytes(version));
|
||||
|
||||
_cachedChainId = block.chainid;
|
||||
_cachedDomainSeparator = _buildDomainSeparator();
|
||||
_cachedThis = address(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the domain separator for the current chain.
|
||||
*/
|
||||
function _domainSeparatorV4() internal view returns (bytes32) {
|
||||
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
|
||||
return _cachedDomainSeparator;
|
||||
} else {
|
||||
return _buildDomainSeparator();
|
||||
}
|
||||
}
|
||||
|
||||
function _buildDomainSeparator() private view returns (bytes32) {
|
||||
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
|
||||
* function returns the hash of the fully encoded EIP712 message for this domain.
|
||||
*
|
||||
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
|
||||
*
|
||||
* ```solidity
|
||||
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
|
||||
* keccak256("Mail(address to,string contents)"),
|
||||
* mailTo,
|
||||
* keccak256(bytes(mailContents))
|
||||
* )));
|
||||
* address signer = ECDSA.recover(digest, signature);
|
||||
* ```
|
||||
*/
|
||||
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
|
||||
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC-5267}.
|
||||
*/
|
||||
function eip712Domain()
|
||||
public
|
||||
view
|
||||
virtual
|
||||
returns (
|
||||
bytes1 fields,
|
||||
string memory name,
|
||||
string memory version,
|
||||
uint256 chainId,
|
||||
address verifyingContract,
|
||||
bytes32 salt,
|
||||
uint256[] memory extensions
|
||||
)
|
||||
{
|
||||
return (
|
||||
hex"0f", // 01111
|
||||
_EIP712Name(),
|
||||
_EIP712Version(),
|
||||
block.chainid,
|
||||
address(this),
|
||||
bytes32(0),
|
||||
new uint256[](0)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev The name parameter for the EIP712 domain.
|
||||
*
|
||||
* NOTE: By default this function reads _name which is an immutable value.
|
||||
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
|
||||
*/
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function _EIP712Name() internal view returns (string memory) {
|
||||
return _name.toStringWithFallback(_nameFallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev The version parameter for the EIP712 domain.
|
||||
*
|
||||
* NOTE: By default this function reads _version which is an immutable value.
|
||||
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
|
||||
*/
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function _EIP712Version() internal view returns (string memory) {
|
||||
return _version.toStringWithFallback(_versionFallback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
/**
|
||||
* @dev Library of standard hash functions.
|
||||
*/
|
||||
library Hashes {
|
||||
/**
|
||||
* @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.
|
||||
*
|
||||
* NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
|
||||
*/
|
||||
function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
|
||||
return a < b ? _efficientKeccak256(a, b) : _efficientKeccak256(b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
|
||||
*/
|
||||
function _efficientKeccak256(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, a)
|
||||
mstore(0x20, b)
|
||||
value := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Hashes} from "./Hashes.sol";
|
||||
|
||||
/**
|
||||
* @dev These functions deal with verification of Merkle Tree proofs.
|
||||
*
|
||||
* The tree and the proofs can be generated using our
|
||||
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
|
||||
* You will find a quickstart guide in the readme.
|
||||
*
|
||||
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
|
||||
* hashing, or use a hash function other than keccak256 for hashing leaves.
|
||||
* This is because the concatenation of a sorted pair of internal nodes in
|
||||
* the Merkle tree could be reinterpreted as a leaf value.
|
||||
* OpenZeppelin's JavaScript library generates Merkle trees that are safe
|
||||
* against this attack out of the box.
|
||||
*/
|
||||
library MerkleProof {
|
||||
/**
|
||||
*@dev The multiproof provided is not valid.
|
||||
*/
|
||||
error MerkleProofInvalidMultiproof();
|
||||
|
||||
/**
|
||||
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
|
||||
* defined by `root`. For this, a `proof` must be provided, containing
|
||||
* sibling hashes on the branch from the leaf to the root of the tree. Each
|
||||
* pair of leaves and each pair of pre-images are assumed to be sorted.
|
||||
*/
|
||||
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
|
||||
return processProof(proof, leaf) == root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calldata version of {verify}
|
||||
*/
|
||||
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
|
||||
return processProofCalldata(proof, leaf) == root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
|
||||
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
|
||||
* hash matches the root of the tree. When processing the proof, the pairs
|
||||
* of leafs & pre-images are assumed to be sorted.
|
||||
*/
|
||||
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
|
||||
bytes32 computedHash = leaf;
|
||||
for (uint256 i = 0; i < proof.length; i++) {
|
||||
computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
|
||||
}
|
||||
return computedHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calldata version of {processProof}
|
||||
*/
|
||||
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
|
||||
bytes32 computedHash = leaf;
|
||||
for (uint256 i = 0; i < proof.length; i++) {
|
||||
computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
|
||||
}
|
||||
return computedHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
|
||||
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*/
|
||||
function multiProofVerify(
|
||||
bytes32[] memory proof,
|
||||
bool[] memory proofFlags,
|
||||
bytes32 root,
|
||||
bytes32[] memory leaves
|
||||
) internal pure returns (bool) {
|
||||
return processMultiProof(proof, proofFlags, leaves) == root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calldata version of {multiProofVerify}
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*/
|
||||
function multiProofVerifyCalldata(
|
||||
bytes32[] calldata proof,
|
||||
bool[] calldata proofFlags,
|
||||
bytes32 root,
|
||||
bytes32[] memory leaves
|
||||
) internal pure returns (bool) {
|
||||
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
|
||||
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
|
||||
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
|
||||
* respectively.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
|
||||
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
|
||||
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
|
||||
*/
|
||||
function processMultiProof(
|
||||
bytes32[] memory proof,
|
||||
bool[] memory proofFlags,
|
||||
bytes32[] memory leaves
|
||||
) internal pure returns (bytes32 merkleRoot) {
|
||||
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
|
||||
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
|
||||
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
|
||||
// the Merkle tree.
|
||||
uint256 leavesLen = leaves.length;
|
||||
uint256 proofLen = proof.length;
|
||||
uint256 totalHashes = proofFlags.length;
|
||||
|
||||
// Check proof validity.
|
||||
if (leavesLen + proofLen != totalHashes + 1) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
|
||||
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
|
||||
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
|
||||
bytes32[] memory hashes = new bytes32[](totalHashes);
|
||||
uint256 leafPos = 0;
|
||||
uint256 hashPos = 0;
|
||||
uint256 proofPos = 0;
|
||||
// At each step, we compute the next hash using two values:
|
||||
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
|
||||
// get the next hash.
|
||||
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
|
||||
// `proof` array.
|
||||
for (uint256 i = 0; i < totalHashes; i++) {
|
||||
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
|
||||
bytes32 b = proofFlags[i]
|
||||
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
|
||||
: proof[proofPos++];
|
||||
hashes[i] = Hashes.commutativeKeccak256(a, b);
|
||||
}
|
||||
|
||||
if (totalHashes > 0) {
|
||||
if (proofPos != proofLen) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
unchecked {
|
||||
return hashes[totalHashes - 1];
|
||||
}
|
||||
} else if (leavesLen > 0) {
|
||||
return leaves[0];
|
||||
} else {
|
||||
return proof[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calldata version of {processMultiProof}.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*/
|
||||
function processMultiProofCalldata(
|
||||
bytes32[] calldata proof,
|
||||
bool[] calldata proofFlags,
|
||||
bytes32[] memory leaves
|
||||
) internal pure returns (bytes32 merkleRoot) {
|
||||
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
|
||||
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
|
||||
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
|
||||
// the Merkle tree.
|
||||
uint256 leavesLen = leaves.length;
|
||||
uint256 proofLen = proof.length;
|
||||
uint256 totalHashes = proofFlags.length;
|
||||
|
||||
// Check proof validity.
|
||||
if (leavesLen + proofLen != totalHashes + 1) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
|
||||
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
|
||||
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
|
||||
bytes32[] memory hashes = new bytes32[](totalHashes);
|
||||
uint256 leafPos = 0;
|
||||
uint256 hashPos = 0;
|
||||
uint256 proofPos = 0;
|
||||
// At each step, we compute the next hash using two values:
|
||||
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
|
||||
// get the next hash.
|
||||
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
|
||||
// `proof` array.
|
||||
for (uint256 i = 0; i < totalHashes; i++) {
|
||||
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
|
||||
bytes32 b = proofFlags[i]
|
||||
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
|
||||
: proof[proofPos++];
|
||||
hashes[i] = Hashes.commutativeKeccak256(a, b);
|
||||
}
|
||||
|
||||
if (totalHashes > 0) {
|
||||
if (proofPos != proofLen) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
unchecked {
|
||||
return hashes[totalHashes - 1];
|
||||
}
|
||||
} else if (leavesLen > 0) {
|
||||
return leaves[0];
|
||||
} else {
|
||||
return proof[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Strings} from "../Strings.sol";
|
||||
|
||||
/**
|
||||
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
|
||||
*
|
||||
* The library provides methods for generating a hash of a message that conforms to the
|
||||
* https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
|
||||
* specifications.
|
||||
*/
|
||||
library MessageHashUtils {
|
||||
/**
|
||||
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
|
||||
* `0x45` (`personal_sign` messages).
|
||||
*
|
||||
* The digest is calculated by prefixing a bytes32 `messageHash` with
|
||||
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
|
||||
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
|
||||
*
|
||||
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
|
||||
* keccak256, although any bytes32 value can be safely used because the final digest will
|
||||
* be re-hashed.
|
||||
*
|
||||
* See {ECDSA-recover}.
|
||||
*/
|
||||
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
|
||||
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
|
||||
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
|
||||
* `0x45` (`personal_sign` messages).
|
||||
*
|
||||
* The digest is calculated by prefixing an arbitrary `message` with
|
||||
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
|
||||
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
|
||||
*
|
||||
* See {ECDSA-recover}.
|
||||
*/
|
||||
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
|
||||
return
|
||||
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
|
||||
* `0x00` (data with intended validator).
|
||||
*
|
||||
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
|
||||
* `validator` address. Then hashing the result.
|
||||
*
|
||||
* See {ECDSA-recover}.
|
||||
*/
|
||||
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
|
||||
return keccak256(abi.encodePacked(hex"19_00", validator, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
|
||||
*
|
||||
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
|
||||
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
|
||||
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
|
||||
*
|
||||
* See {ECDSA-recover}.
|
||||
*/
|
||||
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, hex"19_01")
|
||||
mstore(add(ptr, 0x02), domainSeparator)
|
||||
mstore(add(ptr, 0x22), structHash)
|
||||
digest := keccak256(ptr, 0x42)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {ECDSA} from "./ECDSA.sol";
|
||||
import {IERC1271} from "../../interfaces/IERC1271.sol";
|
||||
|
||||
/**
|
||||
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
|
||||
* signatures from externally owned accounts (EOAs) as well as ERC-1271 signatures from smart contract wallets like
|
||||
* Argent and Safe Wallet (previously Gnosis Safe).
|
||||
*/
|
||||
library SignatureChecker {
|
||||
/**
|
||||
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
|
||||
* signature is validated against that smart contract using ERC-1271, otherwise it's validated using `ECDSA.recover`.
|
||||
*
|
||||
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
|
||||
* change through time. It could return true at block N and false at block N+1 (or the opposite).
|
||||
*/
|
||||
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
|
||||
if (signer.code.length == 0) {
|
||||
(address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature);
|
||||
return err == ECDSA.RecoverError.NoError && recovered == signer;
|
||||
} else {
|
||||
return isValidERC1271SignatureNow(signer, hash, signature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
|
||||
* against the signer smart contract using ERC-1271.
|
||||
*
|
||||
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
|
||||
* change through time. It could return true at block N and false at block N+1 (or the opposite).
|
||||
*/
|
||||
function isValidERC1271SignatureNow(
|
||||
address signer,
|
||||
bytes32 hash,
|
||||
bytes memory signature
|
||||
) internal view returns (bool) {
|
||||
(bool success, bytes memory result) = signer.staticcall(
|
||||
abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
|
||||
);
|
||||
return (success &&
|
||||
result.length >= 32 &&
|
||||
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IERC165} from "./IERC165.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of the {IERC165} interface.
|
||||
*
|
||||
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
|
||||
* for the additional interface id that will be supported. For example:
|
||||
*
|
||||
* ```solidity
|
||||
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
||||
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
abstract contract ERC165 is IERC165 {
|
||||
/**
|
||||
* @dev See {IERC165-supportsInterface}.
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
|
||||
return interfaceId == type(IERC165).interfaceId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IERC165} from "./IERC165.sol";
|
||||
|
||||
/**
|
||||
* @dev Library used to query support of an interface declared via {IERC165}.
|
||||
*
|
||||
* Note that these functions return the actual result of the query: they do not
|
||||
* `revert` if an interface is not supported. It is up to the caller to decide
|
||||
* what to do in these cases.
|
||||
*/
|
||||
library ERC165Checker {
|
||||
// As per the ERC-165 spec, no interface should ever match 0xffffffff
|
||||
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
|
||||
|
||||
/**
|
||||
* @dev Returns true if `account` supports the {IERC165} interface.
|
||||
*/
|
||||
function supportsERC165(address account) internal view returns (bool) {
|
||||
// Any contract that implements ERC-165 must explicitly indicate support of
|
||||
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
|
||||
return
|
||||
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
|
||||
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if `account` supports the interface defined by
|
||||
* `interfaceId`. Support for {IERC165} itself is queried automatically.
|
||||
*
|
||||
* See {IERC165-supportsInterface}.
|
||||
*/
|
||||
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
|
||||
// query support of both ERC-165 as per the spec and support of _interfaceId
|
||||
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a boolean array where each value corresponds to the
|
||||
* interfaces passed in and whether they're supported or not. This allows
|
||||
* you to batch check interfaces for a contract where your expectation
|
||||
* is that some interfaces may not be supported.
|
||||
*
|
||||
* See {IERC165-supportsInterface}.
|
||||
*/
|
||||
function getSupportedInterfaces(
|
||||
address account,
|
||||
bytes4[] memory interfaceIds
|
||||
) internal view returns (bool[] memory) {
|
||||
// an array of booleans corresponding to interfaceIds and whether they're supported or not
|
||||
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
|
||||
|
||||
// query support of ERC-165 itself
|
||||
if (supportsERC165(account)) {
|
||||
// query support of each interface in interfaceIds
|
||||
for (uint256 i = 0; i < interfaceIds.length; i++) {
|
||||
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return interfaceIdsSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if `account` supports all the interfaces defined in
|
||||
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
|
||||
*
|
||||
* Batch-querying can lead to gas savings by skipping repeated checks for
|
||||
* {IERC165} support.
|
||||
*
|
||||
* See {IERC165-supportsInterface}.
|
||||
*/
|
||||
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
|
||||
// query support of ERC-165 itself
|
||||
if (!supportsERC165(account)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// query support of each interface in interfaceIds
|
||||
for (uint256 i = 0; i < interfaceIds.length; i++) {
|
||||
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// all interfaces supported
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Query if a contract implements an interface, does not check ERC-165 support
|
||||
* @param account The address of the contract to query for support of an interface
|
||||
* @param interfaceId The interface identifier, as specified in ERC-165
|
||||
* @return true if the contract at account indicates support of the interface with
|
||||
* identifier interfaceId, false otherwise
|
||||
* @dev Assumes that account contains a contract that supports ERC-165, otherwise
|
||||
* the behavior of this method is undefined. This precondition can be checked
|
||||
* with {supportsERC165}.
|
||||
*
|
||||
* Some precompiled contracts will falsely indicate support for a given interface, so caution
|
||||
* should be exercised when using this function.
|
||||
*
|
||||
* Interface identification is specified in ERC-165.
|
||||
*/
|
||||
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
|
||||
// prepare call
|
||||
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
|
||||
|
||||
// perform static call
|
||||
bool success;
|
||||
uint256 returnSize;
|
||||
uint256 returnValue;
|
||||
assembly {
|
||||
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
|
||||
returnSize := returndatasize()
|
||||
returnValue := mload(0x00)
|
||||
}
|
||||
|
||||
return success && returnSize >= 0x20 && returnValue > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Interface of the ERC-165 standard, as defined in the
|
||||
* https://eips.ethereum.org/EIPS/eip-165[ERC].
|
||||
*
|
||||
* Implementers can declare support of contract interfaces, which can then be
|
||||
* queried by others ({ERC165Checker}).
|
||||
*
|
||||
* For an implementation, see {ERC165}.
|
||||
*/
|
||||
interface IERC165 {
|
||||
/**
|
||||
* @dev Returns true if this contract implements the interface defined by
|
||||
* `interfaceId`. See the corresponding
|
||||
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
|
||||
* to learn more about how these ids are created.
|
||||
*
|
||||
* This function call must use less than 30 000 gas.
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceId) external view returns (bool);
|
||||
}
|
||||
672
lib_openzeppelin_contracts/contracts/utils/math/Math.sol
Normal file
672
lib_openzeppelin_contracts/contracts/utils/math/Math.sol
Normal file
@@ -0,0 +1,672 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Panic} from "../Panic.sol";
|
||||
import {SafeCast} from "./SafeCast.sol";
|
||||
|
||||
/**
|
||||
* @dev Standard math utilities missing in the Solidity language.
|
||||
*/
|
||||
library Math {
|
||||
enum Rounding {
|
||||
Floor, // Toward negative infinity
|
||||
Ceil, // Toward positive infinity
|
||||
Trunc, // Toward zero
|
||||
Expand // Away from zero
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
|
||||
*/
|
||||
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
uint256 c = a + b;
|
||||
if (c < a) return (false, 0);
|
||||
return (true, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
|
||||
*/
|
||||
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
if (b > a) return (false, 0);
|
||||
return (true, a - b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
|
||||
*/
|
||||
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
// benefit is lost if 'b' is also tested.
|
||||
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
|
||||
if (a == 0) return (true, 0);
|
||||
uint256 c = a * b;
|
||||
if (c / a != b) return (false, 0);
|
||||
return (true, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
|
||||
*/
|
||||
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
if (b == 0) return (false, 0);
|
||||
return (true, a / b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
|
||||
*/
|
||||
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
if (b == 0) return (false, 0);
|
||||
return (true, a % b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
|
||||
*
|
||||
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
|
||||
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
|
||||
* one branch when needed, making this function more expensive.
|
||||
*/
|
||||
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
// branchless ternary works because:
|
||||
// b ^ (a ^ b) == a
|
||||
// b ^ 0 == b
|
||||
return b ^ ((a ^ b) * SafeCast.toUint(condition));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the largest of two numbers.
|
||||
*/
|
||||
function max(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return ternary(a > b, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the smallest of two numbers.
|
||||
*/
|
||||
function min(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return ternary(a < b, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the average of two numbers. The result is rounded towards
|
||||
* zero.
|
||||
*/
|
||||
function average(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// (a + b) / 2 can overflow.
|
||||
return (a & b) + (a ^ b) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the ceiling of the division of two numbers.
|
||||
*
|
||||
* This differs from standard division with `/` in that it rounds towards infinity instead
|
||||
* of rounding towards zero.
|
||||
*/
|
||||
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
if (b == 0) {
|
||||
// Guarantee the same behavior as in a regular Solidity division.
|
||||
Panic.panic(Panic.DIVISION_BY_ZERO);
|
||||
}
|
||||
|
||||
// The following calculation ensures accurate ceiling division without overflow.
|
||||
// Since a is non-zero, (a - 1) / b will not overflow.
|
||||
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
|
||||
// but the largest value we can obtain is type(uint256).max - 1, which happens
|
||||
// when a = type(uint256).max and b = 1.
|
||||
unchecked {
|
||||
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
|
||||
* denominator == 0.
|
||||
*
|
||||
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
|
||||
* Uniswap Labs also under MIT license.
|
||||
*/
|
||||
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
|
||||
unchecked {
|
||||
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
|
||||
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
|
||||
// variables such that product = prod1 * 2²⁵⁶ + prod0.
|
||||
uint256 prod0 = x * y; // Least significant 256 bits of the product
|
||||
uint256 prod1; // Most significant 256 bits of the product
|
||||
assembly {
|
||||
let mm := mulmod(x, y, not(0))
|
||||
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
|
||||
}
|
||||
|
||||
// Handle non-overflow cases, 256 by 256 division.
|
||||
if (prod1 == 0) {
|
||||
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
|
||||
// The surrounding unchecked block does not change this fact.
|
||||
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
|
||||
return prod0 / denominator;
|
||||
}
|
||||
|
||||
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
|
||||
if (denominator <= prod1) {
|
||||
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// 512 by 256 division.
|
||||
///////////////////////////////////////////////
|
||||
|
||||
// Make division exact by subtracting the remainder from [prod1 prod0].
|
||||
uint256 remainder;
|
||||
assembly {
|
||||
// Compute remainder using mulmod.
|
||||
remainder := mulmod(x, y, denominator)
|
||||
|
||||
// Subtract 256 bit number from 512 bit number.
|
||||
prod1 := sub(prod1, gt(remainder, prod0))
|
||||
prod0 := sub(prod0, remainder)
|
||||
}
|
||||
|
||||
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
|
||||
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
|
||||
|
||||
uint256 twos = denominator & (0 - denominator);
|
||||
assembly {
|
||||
// Divide denominator by twos.
|
||||
denominator := div(denominator, twos)
|
||||
|
||||
// Divide [prod1 prod0] by twos.
|
||||
prod0 := div(prod0, twos)
|
||||
|
||||
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
|
||||
twos := add(div(sub(0, twos), twos), 1)
|
||||
}
|
||||
|
||||
// Shift in bits from prod1 into prod0.
|
||||
prod0 |= prod1 * twos;
|
||||
|
||||
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
|
||||
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
|
||||
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
|
||||
uint256 inverse = (3 * denominator) ^ 2;
|
||||
|
||||
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
|
||||
// works in modular arithmetic, doubling the correct bits in each step.
|
||||
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
|
||||
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
|
||||
inverse *= 2 - denominator * inverse; // inverse mod 2³²
|
||||
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
|
||||
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
|
||||
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
|
||||
|
||||
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
|
||||
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
|
||||
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1
|
||||
// is no longer required.
|
||||
result = prod0 * inverse;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
|
||||
*/
|
||||
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
|
||||
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
|
||||
*
|
||||
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, expect 0.
|
||||
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
|
||||
*
|
||||
* If the input value is not inversible, 0 is returned.
|
||||
*
|
||||
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Ferma's little theorem and get the
|
||||
* inverse using `Math.modExp(a, n - 2, n)`.
|
||||
*/
|
||||
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
if (n == 0) return 0;
|
||||
|
||||
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
|
||||
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
|
||||
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
|
||||
// ax + ny = 1
|
||||
// ax = 1 + (-y)n
|
||||
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
|
||||
|
||||
// If the remainder is 0 the gcd is n right away.
|
||||
uint256 remainder = a % n;
|
||||
uint256 gcd = n;
|
||||
|
||||
// Therefore the initial coefficients are:
|
||||
// ax + ny = gcd(a, n) = n
|
||||
// 0a + 1n = n
|
||||
int256 x = 0;
|
||||
int256 y = 1;
|
||||
|
||||
while (remainder != 0) {
|
||||
uint256 quotient = gcd / remainder;
|
||||
|
||||
(gcd, remainder) = (
|
||||
// The old remainder is the next gcd to try.
|
||||
remainder,
|
||||
// Compute the next remainder.
|
||||
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
|
||||
// where gcd is at most n (capped to type(uint256).max)
|
||||
gcd - remainder * quotient
|
||||
);
|
||||
|
||||
(x, y) = (
|
||||
// Increment the coefficient of a.
|
||||
y,
|
||||
// Decrement the coefficient of n.
|
||||
// Can overflow, but the result is casted to uint256 so that the
|
||||
// next value of y is "wrapped around" to a value between 0 and n - 1.
|
||||
x - y * int256(quotient)
|
||||
);
|
||||
}
|
||||
|
||||
if (gcd != 1) return 0; // No inverse exists.
|
||||
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
|
||||
*
|
||||
* Requirements:
|
||||
* - modulus can't be zero
|
||||
* - underlying staticcall to precompile must succeed
|
||||
*
|
||||
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
|
||||
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
|
||||
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
|
||||
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
|
||||
* interpreted as 0.
|
||||
*/
|
||||
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
|
||||
(bool success, uint256 result) = tryModExp(b, e, m);
|
||||
if (!success) {
|
||||
Panic.panic(Panic.DIVISION_BY_ZERO);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
|
||||
* It includes a success flag indicating if the operation succeeded. Operation will be marked has failed if trying
|
||||
* to operate modulo 0 or if the underlying precompile reverted.
|
||||
*
|
||||
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
|
||||
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
|
||||
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
|
||||
* of a revert, but the result may be incorrectly interpreted as 0.
|
||||
*/
|
||||
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
|
||||
if (m == 0) return (false, 0);
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
// | Offset | Content | Content (Hex) |
|
||||
// |-----------|------------|--------------------------------------------------------------------|
|
||||
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
|
||||
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
|
||||
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
|
||||
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
|
||||
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
|
||||
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
|
||||
mstore(ptr, 0x20)
|
||||
mstore(add(ptr, 0x20), 0x20)
|
||||
mstore(add(ptr, 0x40), 0x20)
|
||||
mstore(add(ptr, 0x60), b)
|
||||
mstore(add(ptr, 0x80), e)
|
||||
mstore(add(ptr, 0xa0), m)
|
||||
|
||||
// Given the result < m, it's guaranteed to fit in 32 bytes,
|
||||
// so we can use the memory scratch space located at offset 0.
|
||||
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
|
||||
result := mload(0x00)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {modExp} that supports inputs of arbitrary length.
|
||||
*/
|
||||
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
|
||||
(bool success, bytes memory result) = tryModExp(b, e, m);
|
||||
if (!success) {
|
||||
Panic.panic(Panic.DIVISION_BY_ZERO);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
|
||||
*/
|
||||
function tryModExp(
|
||||
bytes memory b,
|
||||
bytes memory e,
|
||||
bytes memory m
|
||||
) internal view returns (bool success, bytes memory result) {
|
||||
if (_zeroBytes(m)) return (false, new bytes(0));
|
||||
|
||||
uint256 mLen = m.length;
|
||||
|
||||
// Encode call args in result and move the free memory pointer
|
||||
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
let dataPtr := add(result, 0x20)
|
||||
// Write result on top of args to avoid allocating extra memory.
|
||||
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
|
||||
// Overwrite the length.
|
||||
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
|
||||
mstore(result, mLen)
|
||||
// Set the memory pointer after the returned data.
|
||||
mstore(0x40, add(dataPtr, mLen))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether the provided byte array is zero.
|
||||
*/
|
||||
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
|
||||
for (uint256 i = 0; i < byteArray.length; ++i) {
|
||||
if (byteArray[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
|
||||
* towards zero.
|
||||
*
|
||||
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
|
||||
* using integer operations.
|
||||
*/
|
||||
function sqrt(uint256 a) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
// Take care of easy edge cases when a == 0 or a == 1
|
||||
if (a <= 1) {
|
||||
return a;
|
||||
}
|
||||
|
||||
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
|
||||
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
|
||||
// the current value as `ε_n = | x_n - sqrt(a) |`.
|
||||
//
|
||||
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
|
||||
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
|
||||
// bigger than any uint256.
|
||||
//
|
||||
// By noticing that
|
||||
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
|
||||
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
|
||||
// to the msb function.
|
||||
uint256 aa = a;
|
||||
uint256 xn = 1;
|
||||
|
||||
if (aa >= (1 << 128)) {
|
||||
aa >>= 128;
|
||||
xn <<= 64;
|
||||
}
|
||||
if (aa >= (1 << 64)) {
|
||||
aa >>= 64;
|
||||
xn <<= 32;
|
||||
}
|
||||
if (aa >= (1 << 32)) {
|
||||
aa >>= 32;
|
||||
xn <<= 16;
|
||||
}
|
||||
if (aa >= (1 << 16)) {
|
||||
aa >>= 16;
|
||||
xn <<= 8;
|
||||
}
|
||||
if (aa >= (1 << 8)) {
|
||||
aa >>= 8;
|
||||
xn <<= 4;
|
||||
}
|
||||
if (aa >= (1 << 4)) {
|
||||
aa >>= 4;
|
||||
xn <<= 2;
|
||||
}
|
||||
if (aa >= (1 << 2)) {
|
||||
xn <<= 1;
|
||||
}
|
||||
|
||||
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
|
||||
//
|
||||
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
|
||||
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
|
||||
// This is going to be our x_0 (and ε_0)
|
||||
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
|
||||
|
||||
// From here, Newton's method give us:
|
||||
// x_{n+1} = (x_n + a / x_n) / 2
|
||||
//
|
||||
// One should note that:
|
||||
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
|
||||
// = ((x_n² + a) / (2 * x_n))² - a
|
||||
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
|
||||
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
|
||||
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
|
||||
// = (x_n² - a)² / (2 * x_n)²
|
||||
// = ((x_n² - a) / (2 * x_n))²
|
||||
// ≥ 0
|
||||
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
|
||||
//
|
||||
// This gives us the proof of quadratic convergence of the sequence:
|
||||
// ε_{n+1} = | x_{n+1} - sqrt(a) |
|
||||
// = | (x_n + a / x_n) / 2 - sqrt(a) |
|
||||
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
|
||||
// = | (x_n - sqrt(a))² / (2 * x_n) |
|
||||
// = | ε_n² / (2 * x_n) |
|
||||
// = ε_n² / | (2 * x_n) |
|
||||
//
|
||||
// For the first iteration, we have a special case where x_0 is known:
|
||||
// ε_1 = ε_0² / | (2 * x_0) |
|
||||
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
|
||||
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
|
||||
// ≤ 2**(e-3) / 3
|
||||
// ≤ 2**(e-3-log2(3))
|
||||
// ≤ 2**(e-4.5)
|
||||
//
|
||||
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
|
||||
// ε_{n+1} = ε_n² / | (2 * x_n) |
|
||||
// ≤ (2**(e-k))² / (2 * 2**(e-1))
|
||||
// ≤ 2**(2*e-2*k) / 2**e
|
||||
// ≤ 2**(e-2*k)
|
||||
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
|
||||
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
|
||||
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
|
||||
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
|
||||
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
|
||||
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
|
||||
|
||||
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
|
||||
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
|
||||
// sqrt(a) or sqrt(a) + 1.
|
||||
return xn - SafeCast.toUint(xn > a / xn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates sqrt(a), following the selected rounding direction.
|
||||
*/
|
||||
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
uint256 result = sqrt(a);
|
||||
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the log in base 2 of a positive value rounded towards zero.
|
||||
* Returns 0 if given 0.
|
||||
*/
|
||||
function log2(uint256 value) internal pure returns (uint256) {
|
||||
uint256 result = 0;
|
||||
uint256 exp;
|
||||
unchecked {
|
||||
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
|
||||
value >>= exp;
|
||||
result += exp;
|
||||
|
||||
result += SafeCast.toUint(value > 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
|
||||
* Returns 0 if given 0.
|
||||
*/
|
||||
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
uint256 result = log2(value);
|
||||
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the log in base 10 of a positive value rounded towards zero.
|
||||
* Returns 0 if given 0.
|
||||
*/
|
||||
function log10(uint256 value) internal pure returns (uint256) {
|
||||
uint256 result = 0;
|
||||
unchecked {
|
||||
if (value >= 10 ** 64) {
|
||||
value /= 10 ** 64;
|
||||
result += 64;
|
||||
}
|
||||
if (value >= 10 ** 32) {
|
||||
value /= 10 ** 32;
|
||||
result += 32;
|
||||
}
|
||||
if (value >= 10 ** 16) {
|
||||
value /= 10 ** 16;
|
||||
result += 16;
|
||||
}
|
||||
if (value >= 10 ** 8) {
|
||||
value /= 10 ** 8;
|
||||
result += 8;
|
||||
}
|
||||
if (value >= 10 ** 4) {
|
||||
value /= 10 ** 4;
|
||||
result += 4;
|
||||
}
|
||||
if (value >= 10 ** 2) {
|
||||
value /= 10 ** 2;
|
||||
result += 2;
|
||||
}
|
||||
if (value >= 10 ** 1) {
|
||||
result += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
|
||||
* Returns 0 if given 0.
|
||||
*/
|
||||
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
uint256 result = log10(value);
|
||||
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the log in base 256 of a positive value rounded towards zero.
|
||||
* Returns 0 if given 0.
|
||||
*
|
||||
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
|
||||
*/
|
||||
function log256(uint256 value) internal pure returns (uint256) {
|
||||
uint256 result = 0;
|
||||
uint256 isGt;
|
||||
unchecked {
|
||||
isGt = SafeCast.toUint(value > (1 << 128) - 1);
|
||||
value >>= isGt * 128;
|
||||
result += isGt * 16;
|
||||
|
||||
isGt = SafeCast.toUint(value > (1 << 64) - 1);
|
||||
value >>= isGt * 64;
|
||||
result += isGt * 8;
|
||||
|
||||
isGt = SafeCast.toUint(value > (1 << 32) - 1);
|
||||
value >>= isGt * 32;
|
||||
result += isGt * 4;
|
||||
|
||||
isGt = SafeCast.toUint(value > (1 << 16) - 1);
|
||||
value >>= isGt * 16;
|
||||
result += isGt * 2;
|
||||
|
||||
result += SafeCast.toUint(value > (1 << 8) - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
|
||||
* Returns 0 if given 0.
|
||||
*/
|
||||
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
uint256 result = log256(value);
|
||||
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
|
||||
*/
|
||||
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
|
||||
return uint8(rounding) % 2 == 1;
|
||||
}
|
||||
}
|
||||
1163
lib_openzeppelin_contracts/contracts/utils/math/SafeCast.sol
Normal file
1163
lib_openzeppelin_contracts/contracts/utils/math/SafeCast.sol
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {SafeCast} from "./SafeCast.sol";
|
||||
|
||||
/**
|
||||
* @dev Standard signed math utilities missing in the Solidity language.
|
||||
*/
|
||||
library SignedMath {
|
||||
/**
|
||||
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
|
||||
*
|
||||
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
|
||||
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
|
||||
* one branch when needed, making this function more expensive.
|
||||
*/
|
||||
function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
|
||||
unchecked {
|
||||
// branchless ternary works because:
|
||||
// b ^ (a ^ b) == a
|
||||
// b ^ 0 == b
|
||||
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the largest of two signed numbers.
|
||||
*/
|
||||
function max(int256 a, int256 b) internal pure returns (int256) {
|
||||
return ternary(a > b, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the smallest of two signed numbers.
|
||||
*/
|
||||
function min(int256 a, int256 b) internal pure returns (int256) {
|
||||
return ternary(a < b, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the average of two signed numbers without overflow.
|
||||
* The result is rounded towards zero.
|
||||
*/
|
||||
function average(int256 a, int256 b) internal pure returns (int256) {
|
||||
// Formula from the book "Hacker's Delight"
|
||||
int256 x = (a & b) + ((a ^ b) >> 1);
|
||||
return x + (int256(uint256(x) >> 255) & (a ^ b));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the absolute unsigned value of a signed value.
|
||||
*/
|
||||
function abs(int256 n) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
|
||||
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
|
||||
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
|
||||
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
|
||||
// the mask will either be `bytes(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
|
||||
int256 mask = n >> 255;
|
||||
|
||||
// A `bytes(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
|
||||
return uint256((n + mask) ^ mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/BitMaps.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Library for managing uint256 to bool mapping in a compact and efficient way, provided the keys are sequential.
|
||||
* Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
|
||||
*
|
||||
* BitMaps pack 256 booleans across each bit of a single 256-bit slot of `uint256` type.
|
||||
* Hence booleans corresponding to 256 _sequential_ indices would only consume a single slot,
|
||||
* unlike the regular `bool` which would consume an entire slot for a single value.
|
||||
*
|
||||
* This results in gas savings in two ways:
|
||||
*
|
||||
* - Setting a zero value to non-zero only once every 256 times
|
||||
* - Accessing the same warm slot for every 256 _sequential_ indices
|
||||
*/
|
||||
library BitMaps {
|
||||
struct BitMap {
|
||||
mapping(uint256 bucket => uint256) _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether the bit at `index` is set.
|
||||
*/
|
||||
function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
|
||||
uint256 bucket = index >> 8;
|
||||
uint256 mask = 1 << (index & 0xff);
|
||||
return bitmap._data[bucket] & mask != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the bit at `index` to the boolean `value`.
|
||||
*/
|
||||
function setTo(BitMap storage bitmap, uint256 index, bool value) internal {
|
||||
if (value) {
|
||||
set(bitmap, index);
|
||||
} else {
|
||||
unset(bitmap, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the bit at `index`.
|
||||
*/
|
||||
function set(BitMap storage bitmap, uint256 index) internal {
|
||||
uint256 bucket = index >> 8;
|
||||
uint256 mask = 1 << (index & 0xff);
|
||||
bitmap._data[bucket] |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unsets the bit at `index`.
|
||||
*/
|
||||
function unset(BitMap storage bitmap, uint256 index) internal {
|
||||
uint256 bucket = index >> 8;
|
||||
uint256 mask = 1 << (index & 0xff);
|
||||
bitmap._data[bucket] &= ~mask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,606 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
|
||||
/**
|
||||
* @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
|
||||
* time, and later looking up past values by block number. See {Votes} as an example.
|
||||
*
|
||||
* To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
|
||||
* checkpoint for the current transaction block using the {push} function.
|
||||
*/
|
||||
library Checkpoints {
|
||||
/**
|
||||
* @dev A value was attempted to be inserted on a past checkpoint.
|
||||
*/
|
||||
error CheckpointUnorderedInsertion();
|
||||
|
||||
struct Trace224 {
|
||||
Checkpoint224[] _checkpoints;
|
||||
}
|
||||
|
||||
struct Checkpoint224 {
|
||||
uint32 _key;
|
||||
uint224 _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
|
||||
*
|
||||
* Returns previous value and new value.
|
||||
*
|
||||
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the
|
||||
* library.
|
||||
*/
|
||||
function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
|
||||
return _insert(self._checkpoints, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
|
||||
* there is none.
|
||||
*/
|
||||
function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
|
||||
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
|
||||
* if there is none.
|
||||
*/
|
||||
function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
|
||||
* if there is none.
|
||||
*
|
||||
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
|
||||
* keys).
|
||||
*/
|
||||
function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
|
||||
uint256 low = 0;
|
||||
uint256 high = len;
|
||||
|
||||
if (len > 5) {
|
||||
uint256 mid = len - Math.sqrt(len);
|
||||
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
|
||||
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
|
||||
*/
|
||||
function latest(Trace224 storage self) internal view returns (uint224) {
|
||||
uint256 pos = self._checkpoints.length;
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
|
||||
* in the most recent checkpoint.
|
||||
*/
|
||||
function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
|
||||
uint256 pos = self._checkpoints.length;
|
||||
if (pos == 0) {
|
||||
return (false, 0, 0);
|
||||
} else {
|
||||
Checkpoint224 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
|
||||
return (true, ckpt._key, ckpt._value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of checkpoint.
|
||||
*/
|
||||
function length(Trace224 storage self) internal view returns (uint256) {
|
||||
return self._checkpoints.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns checkpoint at given position.
|
||||
*/
|
||||
function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
|
||||
return self._checkpoints[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
|
||||
* or by updating the last one.
|
||||
*/
|
||||
function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
|
||||
uint256 pos = self.length;
|
||||
|
||||
if (pos > 0) {
|
||||
Checkpoint224 storage last = _unsafeAccess(self, pos - 1);
|
||||
uint32 lastKey = last._key;
|
||||
uint224 lastValue = last._value;
|
||||
|
||||
// Checkpoint keys must be non-decreasing.
|
||||
if (lastKey > key) {
|
||||
revert CheckpointUnorderedInsertion();
|
||||
}
|
||||
|
||||
// Update or push new checkpoint
|
||||
if (lastKey == key) {
|
||||
_unsafeAccess(self, pos - 1)._value = value;
|
||||
} else {
|
||||
self.push(Checkpoint224({_key: key, _value: value}));
|
||||
}
|
||||
return (lastValue, value);
|
||||
} else {
|
||||
self.push(Checkpoint224({_key: key, _value: value}));
|
||||
return (0, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
|
||||
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
|
||||
* `high`.
|
||||
*
|
||||
* WARNING: `high` should not be greater than the array's length.
|
||||
*/
|
||||
function _upperBinaryLookup(
|
||||
Checkpoint224[] storage self,
|
||||
uint32 key,
|
||||
uint256 low,
|
||||
uint256 high
|
||||
) private view returns (uint256) {
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(self, mid)._key > key) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
|
||||
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
|
||||
* exclusive `high`.
|
||||
*
|
||||
* WARNING: `high` should not be greater than the array's length.
|
||||
*/
|
||||
function _lowerBinaryLookup(
|
||||
Checkpoint224[] storage self,
|
||||
uint32 key,
|
||||
uint256 low,
|
||||
uint256 high
|
||||
) private view returns (uint256) {
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(self, mid)._key < key) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
|
||||
*/
|
||||
function _unsafeAccess(
|
||||
Checkpoint224[] storage self,
|
||||
uint256 pos
|
||||
) private pure returns (Checkpoint224 storage result) {
|
||||
assembly {
|
||||
mstore(0, self.slot)
|
||||
result.slot := add(keccak256(0, 0x20), pos)
|
||||
}
|
||||
}
|
||||
|
||||
struct Trace208 {
|
||||
Checkpoint208[] _checkpoints;
|
||||
}
|
||||
|
||||
struct Checkpoint208 {
|
||||
uint48 _key;
|
||||
uint208 _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
|
||||
*
|
||||
* Returns previous value and new value.
|
||||
*
|
||||
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the
|
||||
* library.
|
||||
*/
|
||||
function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) {
|
||||
return _insert(self._checkpoints, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
|
||||
* there is none.
|
||||
*/
|
||||
function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
|
||||
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
|
||||
* if there is none.
|
||||
*/
|
||||
function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
|
||||
* if there is none.
|
||||
*
|
||||
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
|
||||
* keys).
|
||||
*/
|
||||
function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
|
||||
uint256 low = 0;
|
||||
uint256 high = len;
|
||||
|
||||
if (len > 5) {
|
||||
uint256 mid = len - Math.sqrt(len);
|
||||
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
|
||||
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
|
||||
*/
|
||||
function latest(Trace208 storage self) internal view returns (uint208) {
|
||||
uint256 pos = self._checkpoints.length;
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
|
||||
* in the most recent checkpoint.
|
||||
*/
|
||||
function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) {
|
||||
uint256 pos = self._checkpoints.length;
|
||||
if (pos == 0) {
|
||||
return (false, 0, 0);
|
||||
} else {
|
||||
Checkpoint208 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
|
||||
return (true, ckpt._key, ckpt._value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of checkpoint.
|
||||
*/
|
||||
function length(Trace208 storage self) internal view returns (uint256) {
|
||||
return self._checkpoints.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns checkpoint at given position.
|
||||
*/
|
||||
function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) {
|
||||
return self._checkpoints[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
|
||||
* or by updating the last one.
|
||||
*/
|
||||
function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) {
|
||||
uint256 pos = self.length;
|
||||
|
||||
if (pos > 0) {
|
||||
Checkpoint208 storage last = _unsafeAccess(self, pos - 1);
|
||||
uint48 lastKey = last._key;
|
||||
uint208 lastValue = last._value;
|
||||
|
||||
// Checkpoint keys must be non-decreasing.
|
||||
if (lastKey > key) {
|
||||
revert CheckpointUnorderedInsertion();
|
||||
}
|
||||
|
||||
// Update or push new checkpoint
|
||||
if (lastKey == key) {
|
||||
_unsafeAccess(self, pos - 1)._value = value;
|
||||
} else {
|
||||
self.push(Checkpoint208({_key: key, _value: value}));
|
||||
}
|
||||
return (lastValue, value);
|
||||
} else {
|
||||
self.push(Checkpoint208({_key: key, _value: value}));
|
||||
return (0, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
|
||||
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
|
||||
* `high`.
|
||||
*
|
||||
* WARNING: `high` should not be greater than the array's length.
|
||||
*/
|
||||
function _upperBinaryLookup(
|
||||
Checkpoint208[] storage self,
|
||||
uint48 key,
|
||||
uint256 low,
|
||||
uint256 high
|
||||
) private view returns (uint256) {
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(self, mid)._key > key) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
|
||||
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
|
||||
* exclusive `high`.
|
||||
*
|
||||
* WARNING: `high` should not be greater than the array's length.
|
||||
*/
|
||||
function _lowerBinaryLookup(
|
||||
Checkpoint208[] storage self,
|
||||
uint48 key,
|
||||
uint256 low,
|
||||
uint256 high
|
||||
) private view returns (uint256) {
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(self, mid)._key < key) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
|
||||
*/
|
||||
function _unsafeAccess(
|
||||
Checkpoint208[] storage self,
|
||||
uint256 pos
|
||||
) private pure returns (Checkpoint208 storage result) {
|
||||
assembly {
|
||||
mstore(0, self.slot)
|
||||
result.slot := add(keccak256(0, 0x20), pos)
|
||||
}
|
||||
}
|
||||
|
||||
struct Trace160 {
|
||||
Checkpoint160[] _checkpoints;
|
||||
}
|
||||
|
||||
struct Checkpoint160 {
|
||||
uint96 _key;
|
||||
uint160 _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
|
||||
*
|
||||
* Returns previous value and new value.
|
||||
*
|
||||
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the
|
||||
* library.
|
||||
*/
|
||||
function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
|
||||
return _insert(self._checkpoints, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
|
||||
* there is none.
|
||||
*/
|
||||
function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
|
||||
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
|
||||
* if there is none.
|
||||
*/
|
||||
function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
|
||||
* if there is none.
|
||||
*
|
||||
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
|
||||
* keys).
|
||||
*/
|
||||
function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) {
|
||||
uint256 len = self._checkpoints.length;
|
||||
|
||||
uint256 low = 0;
|
||||
uint256 high = len;
|
||||
|
||||
if (len > 5) {
|
||||
uint256 mid = len - Math.sqrt(len);
|
||||
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
|
||||
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
|
||||
*/
|
||||
function latest(Trace160 storage self) internal view returns (uint160) {
|
||||
uint256 pos = self._checkpoints.length;
|
||||
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
|
||||
* in the most recent checkpoint.
|
||||
*/
|
||||
function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
|
||||
uint256 pos = self._checkpoints.length;
|
||||
if (pos == 0) {
|
||||
return (false, 0, 0);
|
||||
} else {
|
||||
Checkpoint160 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
|
||||
return (true, ckpt._key, ckpt._value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of checkpoint.
|
||||
*/
|
||||
function length(Trace160 storage self) internal view returns (uint256) {
|
||||
return self._checkpoints.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns checkpoint at given position.
|
||||
*/
|
||||
function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) {
|
||||
return self._checkpoints[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
|
||||
* or by updating the last one.
|
||||
*/
|
||||
function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
|
||||
uint256 pos = self.length;
|
||||
|
||||
if (pos > 0) {
|
||||
Checkpoint160 storage last = _unsafeAccess(self, pos - 1);
|
||||
uint96 lastKey = last._key;
|
||||
uint160 lastValue = last._value;
|
||||
|
||||
// Checkpoint keys must be non-decreasing.
|
||||
if (lastKey > key) {
|
||||
revert CheckpointUnorderedInsertion();
|
||||
}
|
||||
|
||||
// Update or push new checkpoint
|
||||
if (lastKey == key) {
|
||||
_unsafeAccess(self, pos - 1)._value = value;
|
||||
} else {
|
||||
self.push(Checkpoint160({_key: key, _value: value}));
|
||||
}
|
||||
return (lastValue, value);
|
||||
} else {
|
||||
self.push(Checkpoint160({_key: key, _value: value}));
|
||||
return (0, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
|
||||
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
|
||||
* `high`.
|
||||
*
|
||||
* WARNING: `high` should not be greater than the array's length.
|
||||
*/
|
||||
function _upperBinaryLookup(
|
||||
Checkpoint160[] storage self,
|
||||
uint96 key,
|
||||
uint256 low,
|
||||
uint256 high
|
||||
) private view returns (uint256) {
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(self, mid)._key > key) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
|
||||
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
|
||||
* exclusive `high`.
|
||||
*
|
||||
* WARNING: `high` should not be greater than the array's length.
|
||||
*/
|
||||
function _lowerBinaryLookup(
|
||||
Checkpoint160[] storage self,
|
||||
uint96 key,
|
||||
uint256 low,
|
||||
uint256 high
|
||||
) private view returns (uint256) {
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(self, mid)._key < key) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
|
||||
*/
|
||||
function _unsafeAccess(
|
||||
Checkpoint160[] storage self,
|
||||
uint256 pos
|
||||
) private pure returns (Checkpoint160 storage result) {
|
||||
assembly {
|
||||
mstore(0, self.slot)
|
||||
result.slot := add(keccak256(0, 0x20), pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
import {Arrays} from "../Arrays.sol";
|
||||
import {Panic} from "../Panic.sol";
|
||||
|
||||
/**
|
||||
* @dev A fixed-size buffer for keeping `bytes32` items in storage.
|
||||
*
|
||||
* This data structure allows for pushing elements to it, and when its length exceeds the specified fixed size,
|
||||
* new items take the place of the oldest element in the buffer, keeping at most `N` elements in the
|
||||
* structure.
|
||||
*
|
||||
* Elements can't be removed but the data structure can be cleared. See {clear}.
|
||||
*
|
||||
* Complexity:
|
||||
* - insertion ({push}): O(1)
|
||||
* - lookup ({last}): O(1)
|
||||
* - inclusion ({includes}): O(N) (worst case)
|
||||
* - reset ({clear}): O(1)
|
||||
*
|
||||
* * The struct is called `Bytes32CircularBuffer`. Other types can be cast to and from `bytes32`. This data structure
|
||||
* can only be used in storage, and not in memory.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract Example {
|
||||
* // Add the library methods
|
||||
* using CircularBuffer for CircularBuffer.Bytes32CircularBuffer;
|
||||
*
|
||||
* // Declare a buffer storage variable
|
||||
* CircularBuffer.Bytes32CircularBuffer private myBuffer;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
library CircularBuffer {
|
||||
/**
|
||||
* @dev Counts the number of items that have been pushed to the buffer. The residuo modulo _data.length indicates
|
||||
* where the next value should be stored.
|
||||
*
|
||||
* Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
|
||||
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
|
||||
* lead to unexpected behavior.
|
||||
*
|
||||
* The last item is at data[(index - 1) % data.length] and the last item is at data[index % data.length]. This
|
||||
* range can wrap around.
|
||||
*/
|
||||
struct Bytes32CircularBuffer {
|
||||
uint256 _count;
|
||||
bytes32[] _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initialize a new CircularBuffer of given size.
|
||||
*
|
||||
* If the CircularBuffer was already setup and used, calling that function again will reset it to a blank state.
|
||||
*
|
||||
* NOTE: The size of the buffer will affect the execution of {includes} function, as it has a complexity of O(N).
|
||||
* Consider a large buffer size may render the function unusable.
|
||||
*/
|
||||
function setup(Bytes32CircularBuffer storage self, uint256 size) internal {
|
||||
clear(self);
|
||||
Arrays.unsafeSetLength(self._data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Clear all data in the buffer without resetting memory, keeping the existing size.
|
||||
*/
|
||||
function clear(Bytes32CircularBuffer storage self) internal {
|
||||
self._count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Push a new value to the buffer. If the buffer is already full, the new value replaces the oldest value in
|
||||
* the buffer.
|
||||
*/
|
||||
function push(Bytes32CircularBuffer storage self, bytes32 value) internal {
|
||||
uint256 index = self._count++;
|
||||
uint256 modulus = self._data.length;
|
||||
Arrays.unsafeAccess(self._data, index % modulus).value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Number of values currently in the buffer. This value is 0 for an empty buffer, and cannot exceed the size of
|
||||
* the buffer.
|
||||
*/
|
||||
function count(Bytes32CircularBuffer storage self) internal view returns (uint256) {
|
||||
return Math.min(self._count, self._data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Length of the buffer. This is the maximum number of elements kepts in the buffer.
|
||||
*/
|
||||
function length(Bytes32CircularBuffer storage self) internal view returns (uint256) {
|
||||
return self._data.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Getter for the i-th value in the buffer, from the end.
|
||||
*
|
||||
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if trying to access an element that was not pushed, or that was
|
||||
* dropped to make room for newer elements.
|
||||
*/
|
||||
function last(Bytes32CircularBuffer storage self, uint256 i) internal view returns (bytes32) {
|
||||
uint256 index = self._count;
|
||||
uint256 modulus = self._data.length;
|
||||
uint256 total = Math.min(index, modulus); // count(self)
|
||||
if (i >= total) {
|
||||
Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
|
||||
}
|
||||
return Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Check if a given value is in the buffer.
|
||||
*/
|
||||
function includes(Bytes32CircularBuffer storage self, bytes32 value) internal view returns (bool) {
|
||||
uint256 index = self._count;
|
||||
uint256 modulus = self._data.length;
|
||||
uint256 total = Math.min(index, modulus); // count(self)
|
||||
for (uint256 i = 0; i < total; ++i) {
|
||||
if (Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Panic} from "../Panic.sol";
|
||||
|
||||
/**
|
||||
* @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
|
||||
* the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
|
||||
* FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
|
||||
* the existing queue contents are left in storage.
|
||||
*
|
||||
* The struct is called `Bytes32Deque`. Other types can be cast to and from `bytes32`. This data structure can only be
|
||||
* used in storage, and not in memory.
|
||||
* ```solidity
|
||||
* DoubleEndedQueue.Bytes32Deque queue;
|
||||
* ```
|
||||
*/
|
||||
library DoubleEndedQueue {
|
||||
/**
|
||||
* @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
|
||||
*
|
||||
* Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
|
||||
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
|
||||
* lead to unexpected behavior.
|
||||
*
|
||||
* The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.
|
||||
*/
|
||||
struct Bytes32Deque {
|
||||
uint128 _begin;
|
||||
uint128 _end;
|
||||
mapping(uint128 index => bytes32) _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Inserts an item at the end of the queue.
|
||||
*
|
||||
* Reverts with {Panic-RESOURCE_ERROR} if the queue is full.
|
||||
*/
|
||||
function pushBack(Bytes32Deque storage deque, bytes32 value) internal {
|
||||
unchecked {
|
||||
uint128 backIndex = deque._end;
|
||||
if (backIndex + 1 == deque._begin) Panic.panic(Panic.RESOURCE_ERROR);
|
||||
deque._data[backIndex] = value;
|
||||
deque._end = backIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes the item at the end of the queue and returns it.
|
||||
*
|
||||
* Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty.
|
||||
*/
|
||||
function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) {
|
||||
unchecked {
|
||||
uint128 backIndex = deque._end;
|
||||
if (backIndex == deque._begin) Panic.panic(Panic.EMPTY_ARRAY_POP);
|
||||
--backIndex;
|
||||
value = deque._data[backIndex];
|
||||
delete deque._data[backIndex];
|
||||
deque._end = backIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Inserts an item at the beginning of the queue.
|
||||
*
|
||||
* Reverts with {Panic-RESOURCE_ERROR} if the queue is full.
|
||||
*/
|
||||
function pushFront(Bytes32Deque storage deque, bytes32 value) internal {
|
||||
unchecked {
|
||||
uint128 frontIndex = deque._begin - 1;
|
||||
if (frontIndex == deque._end) Panic.panic(Panic.RESOURCE_ERROR);
|
||||
deque._data[frontIndex] = value;
|
||||
deque._begin = frontIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes the item at the beginning of the queue and returns it.
|
||||
*
|
||||
* Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty.
|
||||
*/
|
||||
function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) {
|
||||
unchecked {
|
||||
uint128 frontIndex = deque._begin;
|
||||
if (frontIndex == deque._end) Panic.panic(Panic.EMPTY_ARRAY_POP);
|
||||
value = deque._data[frontIndex];
|
||||
delete deque._data[frontIndex];
|
||||
deque._begin = frontIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the item at the beginning of the queue.
|
||||
*
|
||||
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty.
|
||||
*/
|
||||
function front(Bytes32Deque storage deque) internal view returns (bytes32 value) {
|
||||
if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
|
||||
return deque._data[deque._begin];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the item at the end of the queue.
|
||||
*
|
||||
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty.
|
||||
*/
|
||||
function back(Bytes32Deque storage deque) internal view returns (bytes32 value) {
|
||||
if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
|
||||
unchecked {
|
||||
return deque._data[deque._end - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
|
||||
* `length(deque) - 1`.
|
||||
*
|
||||
* Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the index is out of bounds.
|
||||
*/
|
||||
function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) {
|
||||
if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
|
||||
// By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
|
||||
unchecked {
|
||||
return deque._data[deque._begin + uint128(index)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Resets the queue back to being empty.
|
||||
*
|
||||
* NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
|
||||
* out on potential gas refunds.
|
||||
*/
|
||||
function clear(Bytes32Deque storage deque) internal {
|
||||
deque._begin = 0;
|
||||
deque._end = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of items in the queue.
|
||||
*/
|
||||
function length(Bytes32Deque storage deque) internal view returns (uint256) {
|
||||
unchecked {
|
||||
return uint256(deque._end - deque._begin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the queue is empty.
|
||||
*/
|
||||
function empty(Bytes32Deque storage deque) internal view returns (bool) {
|
||||
return deque._end == deque._begin;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,913 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {EnumerableSet} from "./EnumerableSet.sol";
|
||||
|
||||
/**
|
||||
* @dev Library for managing an enumerable variant of Solidity's
|
||||
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
|
||||
* type.
|
||||
*
|
||||
* Maps have the following properties:
|
||||
*
|
||||
* - Entries are added, removed, and checked for existence in constant time
|
||||
* (O(1)).
|
||||
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
|
||||
*
|
||||
* ```solidity
|
||||
* contract Example {
|
||||
* // Add the library methods
|
||||
* using EnumerableMap for EnumerableMap.UintToAddressMap;
|
||||
*
|
||||
* // Declare a set state variable
|
||||
* EnumerableMap.UintToAddressMap private myMap;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The following map types are supported:
|
||||
*
|
||||
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
|
||||
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
|
||||
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
|
||||
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
|
||||
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
|
||||
* - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0
|
||||
* - `address -> address` (`AddressToAddressMap`) since v5.1.0
|
||||
* - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0
|
||||
* - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.0
|
||||
*
|
||||
* [WARNING]
|
||||
* ====
|
||||
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
|
||||
* unusable.
|
||||
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
|
||||
*
|
||||
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
|
||||
* array of EnumerableMap.
|
||||
* ====
|
||||
*/
|
||||
library EnumerableMap {
|
||||
using EnumerableSet for EnumerableSet.Bytes32Set;
|
||||
|
||||
// To implement this library for multiple types with as little code repetition as possible, we write it in
|
||||
// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
|
||||
// and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.
|
||||
// This means that we can only create new EnumerableMaps for types that fit in bytes32.
|
||||
|
||||
/**
|
||||
* @dev Query for a nonexistent map key.
|
||||
*/
|
||||
error EnumerableMapNonexistentKey(bytes32 key);
|
||||
|
||||
struct Bytes32ToBytes32Map {
|
||||
// Storage of keys
|
||||
EnumerableSet.Bytes32Set _keys;
|
||||
mapping(bytes32 key => bytes32) _values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
|
||||
map._values[key] = value;
|
||||
return map._keys.add(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a key-value pair from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
|
||||
delete map._values[key];
|
||||
return map._keys.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
|
||||
return map._keys.contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of key-value pairs in the map. O(1).
|
||||
*/
|
||||
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
|
||||
return map._keys.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
|
||||
*
|
||||
* Note that there are no guarantees on the ordering of entries inside the
|
||||
* array, and it may change when more entries are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
|
||||
bytes32 key = map._keys.at(index);
|
||||
return (key, map._values[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
|
||||
bytes32 value = map._values[key];
|
||||
if (value == bytes32(0)) {
|
||||
return (contains(map, key), bytes32(0));
|
||||
} else {
|
||||
return (true, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
|
||||
bytes32 value = map._values[key];
|
||||
if (value == 0 && !contains(map, key)) {
|
||||
revert EnumerableMapNonexistentKey(key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
|
||||
return map._keys.values();
|
||||
}
|
||||
|
||||
// UintToUintMap
|
||||
|
||||
struct UintToUintMap {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
|
||||
return set(map._inner, bytes32(key), bytes32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
|
||||
return remove(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
|
||||
return contains(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(UintToUintMap storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (uint256(key), uint256(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
|
||||
return (success, uint256(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
|
||||
return uint256(get(map._inner, bytes32(key)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
uint256[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// UintToAddressMap
|
||||
|
||||
struct UintToAddressMap {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
|
||||
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
|
||||
return remove(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
|
||||
return contains(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(UintToAddressMap storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (uint256(key), address(uint160(uint256(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
|
||||
return (success, address(uint160(uint256(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
|
||||
return address(uint160(uint256(get(map._inner, bytes32(key)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
uint256[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// UintToBytes32Map
|
||||
|
||||
struct UintToBytes32Map {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) {
|
||||
return set(map._inner, bytes32(key), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(UintToBytes32Map storage map, uint256 key) internal returns (bool) {
|
||||
return remove(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(UintToBytes32Map storage map, uint256 key) internal view returns (bool) {
|
||||
return contains(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(UintToBytes32Map storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(UintToBytes32Map storage map, uint256 index) internal view returns (uint256, bytes32) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (uint256(key), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool, bytes32) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
|
||||
return (success, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) {
|
||||
return get(map._inner, bytes32(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(UintToBytes32Map storage map) internal view returns (uint256[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
uint256[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// AddressToUintMap
|
||||
|
||||
struct AddressToUintMap {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
|
||||
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
|
||||
return remove(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
|
||||
return contains(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(AddressToUintMap storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (address(uint160(uint256(key))), uint256(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
|
||||
return (success, uint256(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
|
||||
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
address[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// AddressToAddressMap
|
||||
|
||||
struct AddressToAddressMap {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) {
|
||||
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(AddressToAddressMap storage map, address key) internal returns (bool) {
|
||||
return remove(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(AddressToAddressMap storage map, address key) internal view returns (bool) {
|
||||
return contains(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(AddressToAddressMap storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(AddressToAddressMap storage map, uint256 index) internal view returns (address, address) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (address(uint160(uint256(key))), address(uint160(uint256(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool, address) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
|
||||
return (success, address(uint160(uint256(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(AddressToAddressMap storage map, address key) internal view returns (address) {
|
||||
return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key)))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(AddressToAddressMap storage map) internal view returns (address[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
address[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// AddressToBytes32Map
|
||||
|
||||
struct AddressToBytes32Map {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) {
|
||||
return set(map._inner, bytes32(uint256(uint160(key))), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(AddressToBytes32Map storage map, address key) internal returns (bool) {
|
||||
return remove(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(AddressToBytes32Map storage map, address key) internal view returns (bool) {
|
||||
return contains(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(AddressToBytes32Map storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(AddressToBytes32Map storage map, uint256 index) internal view returns (address, bytes32) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (address(uint160(uint256(key))), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool, bytes32) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
|
||||
return (success, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {
|
||||
return get(map._inner, bytes32(uint256(uint160(key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(AddressToBytes32Map storage map) internal view returns (address[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
address[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Bytes32ToUintMap
|
||||
|
||||
struct Bytes32ToUintMap {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
|
||||
return set(map._inner, key, bytes32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
|
||||
return remove(map._inner, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
|
||||
return contains(map._inner, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (key, uint256(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, key);
|
||||
return (success, uint256(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
|
||||
return uint256(get(map._inner, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
bytes32[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Bytes32ToAddressMap
|
||||
|
||||
struct Bytes32ToAddressMap {
|
||||
Bytes32ToBytes32Map _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds a key-value pair to a map, or updates the value for an existing
|
||||
* key. O(1).
|
||||
*
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) {
|
||||
return set(map._inner, key, bytes32(uint256(uint160(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a map. O(1).
|
||||
*
|
||||
* Returns true if the key was removed from the map, that is if it was present.
|
||||
*/
|
||||
function remove(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) {
|
||||
return remove(map._inner, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the key is in the map. O(1).
|
||||
*/
|
||||
function contains(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool) {
|
||||
return contains(map._inner, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the map. O(1).
|
||||
*/
|
||||
function length(Bytes32ToAddressMap storage map) internal view returns (uint256) {
|
||||
return length(map._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the element stored at position `index` in the map. O(1).
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32, address) {
|
||||
(bytes32 key, bytes32 value) = at(map._inner, index);
|
||||
return (key, address(uint160(uint256(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tries to returns the value associated with `key`. O(1).
|
||||
* Does not revert if `key` is not in the map.
|
||||
*/
|
||||
function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool, address) {
|
||||
(bool success, bytes32 value) = tryGet(map._inner, key);
|
||||
return (success, address(uint160(uint256(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value associated with `key`. O(1).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `key` must be in the map.
|
||||
*/
|
||||
function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) {
|
||||
return address(uint160(uint256(get(map._inner, key))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the an array containing all the keys
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function keys(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) {
|
||||
bytes32[] memory store = keys(map._inner);
|
||||
bytes32[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Library for managing
|
||||
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
|
||||
* types.
|
||||
*
|
||||
* Sets have the following properties:
|
||||
*
|
||||
* - Elements are added, removed, and checked for existence in constant time
|
||||
* (O(1)).
|
||||
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
|
||||
*
|
||||
* ```solidity
|
||||
* contract Example {
|
||||
* // Add the library methods
|
||||
* using EnumerableSet for EnumerableSet.AddressSet;
|
||||
*
|
||||
* // Declare a set state variable
|
||||
* EnumerableSet.AddressSet private mySet;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
|
||||
* and `uint256` (`UintSet`) are supported.
|
||||
*
|
||||
* [WARNING]
|
||||
* ====
|
||||
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
|
||||
* unusable.
|
||||
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
|
||||
*
|
||||
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
|
||||
* array of EnumerableSet.
|
||||
* ====
|
||||
*/
|
||||
library EnumerableSet {
|
||||
// To implement this library for multiple types with as little code
|
||||
// repetition as possible, we write it in terms of a generic Set type with
|
||||
// bytes32 values.
|
||||
// The Set implementation uses private functions, and user-facing
|
||||
// implementations (such as AddressSet) are just wrappers around the
|
||||
// underlying Set.
|
||||
// This means that we can only create new EnumerableSets for types that fit
|
||||
// in bytes32.
|
||||
|
||||
struct Set {
|
||||
// Storage of set values
|
||||
bytes32[] _values;
|
||||
// Position is the index of the value in the `values` array plus 1.
|
||||
// Position 0 is used to mean a value is not in the set.
|
||||
mapping(bytes32 value => uint256) _positions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add a value to a set. O(1).
|
||||
*
|
||||
* Returns true if the value was added to the set, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function _add(Set storage set, bytes32 value) private returns (bool) {
|
||||
if (!_contains(set, value)) {
|
||||
set._values.push(value);
|
||||
// The value is stored at length-1, but we add 1 to all indexes
|
||||
// and use 0 as a sentinel value
|
||||
set._positions[value] = set._values.length;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a set. O(1).
|
||||
*
|
||||
* Returns true if the value was removed from the set, that is if it was
|
||||
* present.
|
||||
*/
|
||||
function _remove(Set storage set, bytes32 value) private returns (bool) {
|
||||
// We cache the value's position to prevent multiple reads from the same storage slot
|
||||
uint256 position = set._positions[value];
|
||||
|
||||
if (position != 0) {
|
||||
// Equivalent to contains(set, value)
|
||||
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
|
||||
// the array, and then remove the last element (sometimes called as 'swap and pop').
|
||||
// This modifies the order of the array, as noted in {at}.
|
||||
|
||||
uint256 valueIndex = position - 1;
|
||||
uint256 lastIndex = set._values.length - 1;
|
||||
|
||||
if (valueIndex != lastIndex) {
|
||||
bytes32 lastValue = set._values[lastIndex];
|
||||
|
||||
// Move the lastValue to the index where the value to delete is
|
||||
set._values[valueIndex] = lastValue;
|
||||
// Update the tracked position of the lastValue (that was just moved)
|
||||
set._positions[lastValue] = position;
|
||||
}
|
||||
|
||||
// Delete the slot where the moved value was stored
|
||||
set._values.pop();
|
||||
|
||||
// Delete the tracked position for the deleted slot
|
||||
delete set._positions[value];
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set. O(1).
|
||||
*/
|
||||
function _contains(Set storage set, bytes32 value) private view returns (bool) {
|
||||
return set._positions[value] != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of values on the set. O(1).
|
||||
*/
|
||||
function _length(Set storage set) private view returns (uint256) {
|
||||
return set._values.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||
*
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function _at(Set storage set, uint256 index) private view returns (bytes32) {
|
||||
return set._values[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the entire set in an array
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function _values(Set storage set) private view returns (bytes32[] memory) {
|
||||
return set._values;
|
||||
}
|
||||
|
||||
// Bytes32Set
|
||||
|
||||
struct Bytes32Set {
|
||||
Set _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add a value to a set. O(1).
|
||||
*
|
||||
* Returns true if the value was added to the set, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
|
||||
return _add(set._inner, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a set. O(1).
|
||||
*
|
||||
* Returns true if the value was removed from the set, that is if it was
|
||||
* present.
|
||||
*/
|
||||
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
|
||||
return _remove(set._inner, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set. O(1).
|
||||
*/
|
||||
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
|
||||
return _contains(set._inner, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of values in the set. O(1).
|
||||
*/
|
||||
function length(Bytes32Set storage set) internal view returns (uint256) {
|
||||
return _length(set._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||
*
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
|
||||
return _at(set._inner, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the entire set in an array
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
|
||||
bytes32[] memory store = _values(set._inner);
|
||||
bytes32[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// AddressSet
|
||||
|
||||
struct AddressSet {
|
||||
Set _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add a value to a set. O(1).
|
||||
*
|
||||
* Returns true if the value was added to the set, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function add(AddressSet storage set, address value) internal returns (bool) {
|
||||
return _add(set._inner, bytes32(uint256(uint160(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a set. O(1).
|
||||
*
|
||||
* Returns true if the value was removed from the set, that is if it was
|
||||
* present.
|
||||
*/
|
||||
function remove(AddressSet storage set, address value) internal returns (bool) {
|
||||
return _remove(set._inner, bytes32(uint256(uint160(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set. O(1).
|
||||
*/
|
||||
function contains(AddressSet storage set, address value) internal view returns (bool) {
|
||||
return _contains(set._inner, bytes32(uint256(uint160(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of values in the set. O(1).
|
||||
*/
|
||||
function length(AddressSet storage set) internal view returns (uint256) {
|
||||
return _length(set._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||
*
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(AddressSet storage set, uint256 index) internal view returns (address) {
|
||||
return address(uint160(uint256(_at(set._inner, index))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the entire set in an array
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function values(AddressSet storage set) internal view returns (address[] memory) {
|
||||
bytes32[] memory store = _values(set._inner);
|
||||
address[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// UintSet
|
||||
|
||||
struct UintSet {
|
||||
Set _inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add a value to a set. O(1).
|
||||
*
|
||||
* Returns true if the value was added to the set, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function add(UintSet storage set, uint256 value) internal returns (bool) {
|
||||
return _add(set._inner, bytes32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes a value from a set. O(1).
|
||||
*
|
||||
* Returns true if the value was removed from the set, that is if it was
|
||||
* present.
|
||||
*/
|
||||
function remove(UintSet storage set, uint256 value) internal returns (bool) {
|
||||
return _remove(set._inner, bytes32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set. O(1).
|
||||
*/
|
||||
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
|
||||
return _contains(set._inner, bytes32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of values in the set. O(1).
|
||||
*/
|
||||
function length(UintSet storage set) internal view returns (uint256) {
|
||||
return _length(set._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||
*
|
||||
* Note that there are no guarantees on the ordering of values inside the
|
||||
* array, and it may change when more values are added or removed.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `index` must be strictly less than {length}.
|
||||
*/
|
||||
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
|
||||
return uint256(_at(set._inner, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the entire set in an array
|
||||
*
|
||||
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||
*/
|
||||
function values(UintSet storage set) internal view returns (uint256[] memory) {
|
||||
bytes32[] memory store = _values(set._inner);
|
||||
uint256[] memory result;
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {Hashes} from "../cryptography/Hashes.sol";
|
||||
import {Arrays} from "../Arrays.sol";
|
||||
import {Panic} from "../Panic.sol";
|
||||
|
||||
/**
|
||||
* @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures.
|
||||
*
|
||||
* Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a
|
||||
* non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not
|
||||
* stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}.
|
||||
*
|
||||
* A tree is defined by the following parameters:
|
||||
*
|
||||
* * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth.
|
||||
* * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree.
|
||||
* * Hashing function: A cryptographic hash function used to produce internal nodes.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library MerkleTree {
|
||||
/**
|
||||
* @dev A complete `bytes32` Merkle tree.
|
||||
*
|
||||
* The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup.
|
||||
*
|
||||
* The hashing function used during initialization to compute the `zeros` values (value of a node at a given depth
|
||||
* for which the subtree is full of zero leaves). This function is kept in the structure for handling insertions.
|
||||
*
|
||||
* Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
|
||||
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
|
||||
* lead to unexpected behavior.
|
||||
*
|
||||
* NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to
|
||||
* store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or
|
||||
* {Checkpoints}).
|
||||
*
|
||||
* WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree.
|
||||
*/
|
||||
struct Bytes32PushTree {
|
||||
uint256 _nextLeafIndex;
|
||||
bytes32[] _sides;
|
||||
bytes32[] _zeros;
|
||||
function(bytes32, bytes32) view returns (bytes32) _fnHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initialize a {Bytes32PushTree} using {Hashes-commutativeKeccak256} to hash internal nodes.
|
||||
* The capacity of the tree (i.e. number of leaves) is set to `2**levels`.
|
||||
*
|
||||
* Calling this function on MerkleTree that was already setup and used will reset it to a blank state.
|
||||
*
|
||||
* IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing
|
||||
* empty leaves. It should be a value that is not expected to be part of the tree.
|
||||
*/
|
||||
function setup(Bytes32PushTree storage self, uint8 levels, bytes32 zero) internal returns (bytes32 initialRoot) {
|
||||
return setup(self, levels, zero, Hashes.commutativeKeccak256);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {setup}, but allows to specify a custom hashing function.
|
||||
*
|
||||
* IMPORTANT: Providing a custom hashing function is a security-sensitive operation since it may
|
||||
* compromise the soundness of the tree. Consider using functions from {Hashes}.
|
||||
*/
|
||||
function setup(
|
||||
Bytes32PushTree storage self,
|
||||
uint8 levels,
|
||||
bytes32 zero,
|
||||
function(bytes32, bytes32) view returns (bytes32) fnHash
|
||||
) internal returns (bytes32 initialRoot) {
|
||||
// Store depth in the dynamic array
|
||||
Arrays.unsafeSetLength(self._sides, levels);
|
||||
Arrays.unsafeSetLength(self._zeros, levels);
|
||||
|
||||
// Build each root of zero-filled subtrees
|
||||
bytes32 currentZero = zero;
|
||||
for (uint32 i = 0; i < levels; ++i) {
|
||||
Arrays.unsafeAccess(self._zeros, i).value = currentZero;
|
||||
currentZero = fnHash(currentZero, currentZero);
|
||||
}
|
||||
|
||||
// Set the first root
|
||||
self._nextLeafIndex = 0;
|
||||
self._fnHash = fnHash;
|
||||
|
||||
return currentZero;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the
|
||||
* tree, and the resulting root.
|
||||
*
|
||||
* Hashing the leaf before calling this function is recommended as a protection against
|
||||
* second pre-image attacks.
|
||||
*/
|
||||
function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) {
|
||||
// Cache read
|
||||
uint256 levels = self._zeros.length;
|
||||
function(bytes32, bytes32) view returns (bytes32) fnHash = self._fnHash;
|
||||
|
||||
// Get leaf index
|
||||
index = self._nextLeafIndex++;
|
||||
|
||||
// Check if tree is full.
|
||||
if (index >= 1 << levels) {
|
||||
Panic.panic(Panic.RESOURCE_ERROR);
|
||||
}
|
||||
|
||||
// Rebuild branch from leaf to root
|
||||
uint256 currentIndex = index;
|
||||
bytes32 currentLevelHash = leaf;
|
||||
for (uint32 i = 0; i < levels; i++) {
|
||||
// Reaching the parent node, is currentLevelHash the left child?
|
||||
bool isLeft = currentIndex % 2 == 0;
|
||||
|
||||
// If so, next time we will come from the right, so we need to save it
|
||||
if (isLeft) {
|
||||
Arrays.unsafeAccess(self._sides, i).value = currentLevelHash;
|
||||
}
|
||||
|
||||
// Compute the current node hash by using the hash function
|
||||
// with either the its sibling (side) or the zero value for that level.
|
||||
currentLevelHash = fnHash(
|
||||
isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value,
|
||||
isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash
|
||||
);
|
||||
|
||||
// Update node index
|
||||
currentIndex >>= 1;
|
||||
}
|
||||
|
||||
return (index, currentLevelHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tree's depth (set at initialization)
|
||||
*/
|
||||
function depth(Bytes32PushTree storage self) internal view returns (uint256) {
|
||||
return self._zeros.length;
|
||||
}
|
||||
}
|
||||
130
lib_openzeppelin_contracts/contracts/utils/types/Time.sol
Normal file
130
lib_openzeppelin_contracts/contracts/utils/types/Time.sol
Normal file
@@ -0,0 +1,130 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
import {SafeCast} from "../math/SafeCast.sol";
|
||||
|
||||
/**
|
||||
* @dev This library provides helpers for manipulating time-related objects.
|
||||
*
|
||||
* It uses the following types:
|
||||
* - `uint48` for timepoints
|
||||
* - `uint32` for durations
|
||||
*
|
||||
* While the library doesn't provide specific types for timepoints and duration, it does provide:
|
||||
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
|
||||
* - additional helper functions
|
||||
*/
|
||||
library Time {
|
||||
using Time for *;
|
||||
|
||||
/**
|
||||
* @dev Get the block timestamp as a Timepoint.
|
||||
*/
|
||||
function timestamp() internal view returns (uint48) {
|
||||
return SafeCast.toUint48(block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the block number as a Timepoint.
|
||||
*/
|
||||
function blockNumber() internal view returns (uint48) {
|
||||
return SafeCast.toUint48(block.number);
|
||||
}
|
||||
|
||||
// ==================================================== Delay =====================================================
|
||||
/**
|
||||
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
|
||||
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
|
||||
* This allows updating the delay applied to some operation while keeping some guarantees.
|
||||
*
|
||||
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
|
||||
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
|
||||
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
|
||||
* still apply for some time.
|
||||
*
|
||||
*
|
||||
* The `Delay` type is 112 bits long, and packs the following:
|
||||
*
|
||||
* ```
|
||||
* | [uint48]: effect date (timepoint)
|
||||
* | | [uint32]: value before (duration)
|
||||
* ↓ ↓ ↓ [uint32]: value after (duration)
|
||||
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
|
||||
* ```
|
||||
*
|
||||
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
|
||||
* supported.
|
||||
*/
|
||||
type Delay is uint112;
|
||||
|
||||
/**
|
||||
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
|
||||
*/
|
||||
function toDelay(uint32 duration) internal pure returns (Delay) {
|
||||
return Delay.wrap(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
|
||||
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
|
||||
*/
|
||||
function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) {
|
||||
(uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack();
|
||||
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
|
||||
* effect timepoint is 0, then the pending value should not be considered.
|
||||
*/
|
||||
function getFull(Delay self) internal view returns (uint32, uint32, uint48) {
|
||||
return _getFullAt(self, timestamp());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the current value.
|
||||
*/
|
||||
function get(Delay self) internal view returns (uint32) {
|
||||
(uint32 delay, , ) = self.getFull();
|
||||
return delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
|
||||
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
|
||||
* new delay becomes effective.
|
||||
*/
|
||||
function withUpdate(
|
||||
Delay self,
|
||||
uint32 newValue,
|
||||
uint32 minSetback
|
||||
) internal view returns (Delay updatedDelay, uint48 effect) {
|
||||
uint32 value = self.get();
|
||||
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
|
||||
effect = timestamp() + setback;
|
||||
return (pack(value, newValue, effect), effect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
|
||||
*/
|
||||
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
|
||||
uint112 raw = Delay.unwrap(self);
|
||||
|
||||
valueAfter = uint32(raw);
|
||||
valueBefore = uint32(raw >> 32);
|
||||
effect = uint48(raw >> 64);
|
||||
|
||||
return (valueBefore, valueAfter, effect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev pack the components into a Delay object.
|
||||
*/
|
||||
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
|
||||
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user