refactor: move brother_node development artifact to dev/test-nodes subdirectory
Development Artifact Cleanup: ✅ BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location - dev/test-nodes/brother_node/: Moved from root directory for better organization - Contains development configuration, test logs, and test chain data - No impact on production systems - purely development/testing artifact ✅ DEVELOPMENT ARTIFACTS IDENTIFIED: - Chain ID: aitbc-brother-chain (test/development chain) - Ports: 8010 (P2P) and 8011 (RPC) - different from production - Environment: .env file with test configuration - Logs: rpc.log and node.log from development testing session (March 15, 2026) ✅ ROOT DIRECTORY CLEANUP: Removed development clutter from production directory - brother_node/ moved to dev/test-nodes/brother_node/ - Root directory now contains only production-ready components - Development artifacts properly organized in dev/ subdirectory DIRECTORY STRUCTURE IMPROVEMENT: 📁 dev/test-nodes/: Development and testing node configurations 🏗️ Root Directory: Clean production structure with only essential components 🧪 Development Isolation: Test environments separated from production BENEFITS: ✅ Clean Production Directory: No development artifacts in root ✅ Better Organization: Development nodes grouped in dev/ subdirectory ✅ Clear Separation: Production vs development environments clearly distinguished ✅ Maintainability: Easier to identify and manage development components RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
This commit is contained in:
149
dev/env/node_modules/@openzeppelin/contracts/utils/Address.sol
generated
vendored
Executable file
149
dev/env/node_modules/@openzeppelin/contracts/utils/Address.sol
generated
vendored
Executable file
@@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.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, bytes memory returndata) = recipient.call{value: amount}("");
|
||||
if (!success) {
|
||||
_revert(returndata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
assembly ("memory-safe") {
|
||||
revert(add(returndata, 0x20), mload(returndata))
|
||||
}
|
||||
} else {
|
||||
revert Errors.FailedCall();
|
||||
}
|
||||
}
|
||||
}
|
||||
552
dev/env/node_modules/@openzeppelin/contracts/utils/Arrays.sol
generated
vendored
Executable file
552
dev/env/node_modules/@openzeppelin/contracts/utils/Arrays.sol
generated
vendored
Executable file
@@ -0,0 +1,552 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Comparators} from "./Comparators.sol";
|
||||
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 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.
|
||||
*
|
||||
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
|
||||
*/
|
||||
function sort(
|
||||
uint256[] memory array,
|
||||
function(uint256, uint256) pure returns (bool) comp
|
||||
) internal pure returns (uint256[] memory) {
|
||||
_quickSort(_begin(array), _end(array), 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(array, Comparators.lt);
|
||||
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.
|
||||
*
|
||||
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
|
||||
*/
|
||||
function sort(
|
||||
address[] memory array,
|
||||
function(address, address) pure returns (bool) comp
|
||||
) internal pure returns (address[] memory) {
|
||||
sort(_castToUint256Array(array), _castToUint256Comp(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(_castToUint256Array(array), Comparators.lt);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
|
||||
*/
|
||||
function sort(
|
||||
bytes32[] memory array,
|
||||
function(bytes32, bytes32) pure returns (bool) comp
|
||||
) internal pure returns (bytes32[] memory) {
|
||||
sort(_castToUint256Array(array), _castToUint256Comp(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(_castToUint256Array(array), Comparators.lt);
|
||||
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(uint256, uint256) pure returns (bool) comp) private pure {
|
||||
unchecked {
|
||||
if (end - begin < 0x40) return;
|
||||
|
||||
// Use first element as pivot
|
||||
uint256 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(uint256[] memory array) private pure returns (uint256 ptr) {
|
||||
assembly ("memory-safe") {
|
||||
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(uint256[] memory array) private pure returns (uint256 ptr) {
|
||||
unchecked {
|
||||
return _begin(array) + array.length * 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load memory word (as a uint256) at location `ptr`.
|
||||
*/
|
||||
function _mload(uint256 ptr) private pure returns (uint256 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 Helper: low level cast address memory array to uint256 memory array
|
||||
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
|
||||
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast address comp function to uint256 comp function
|
||||
function _castToUint256Comp(
|
||||
function(address, address) pure returns (bool) input
|
||||
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
|
||||
function _castToUint256Comp(
|
||||
function(bytes32, bytes32) pure returns (bool) input
|
||||
) private pure returns (function(uint256, uint256) 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;
|
||||
assembly ("memory-safe") {
|
||||
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;
|
||||
assembly ("memory-safe") {
|
||||
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;
|
||||
assembly ("memory-safe") {
|
||||
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 unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {
|
||||
bytes32 slot;
|
||||
assembly ("memory-safe") {
|
||||
slot := arr.slot
|
||||
}
|
||||
return slot.deriveArray().offset(pos).getBytesSlot();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {
|
||||
bytes32 slot;
|
||||
assembly ("memory-safe") {
|
||||
slot := arr.slot
|
||||
}
|
||||
return slot.deriveArray().offset(pos).getStringSlot();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 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(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory 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(string[] memory arr, uint256 pos) internal pure returns (string memory res) {
|
||||
assembly {
|
||||
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of a 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 {
|
||||
assembly ("memory-safe") {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of a 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 {
|
||||
assembly ("memory-safe") {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of a 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 {
|
||||
assembly ("memory-safe") {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of a 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(bytes[] storage array, uint256 len) internal {
|
||||
assembly ("memory-safe") {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Helper to set the length of a 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(string[] storage array, uint256 len) internal {
|
||||
assembly ("memory-safe") {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
119
dev/env/node_modules/@openzeppelin/contracts/utils/Base64.sol
generated
vendored
Executable file
119
dev/env/node_modules/@openzeppelin/contracts/utils/Base64.sol
generated
vendored
Executable file
@@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (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.
|
||||
* Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648].
|
||||
*/
|
||||
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` -> Prepare for division rounding up
|
||||
// - `/ 3` -> Number of 3-bytes chunks (rounded up)
|
||||
// - `4 *` -> 4 characters for each chunk
|
||||
// This is equivalent to: 4 * Math.ceil(data.length / 3)
|
||||
//
|
||||
// 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 * data.length` -> 4 characters for each chunk
|
||||
// - ` + 2` -> Prepare for division rounding up
|
||||
// - `/ 3` -> Number of 3-bytes chunks (rounded up)
|
||||
// This is equivalent to: Math.ceil((4 * data.length) / 3)
|
||||
uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;
|
||||
|
||||
string memory result = new string(resultLength);
|
||||
|
||||
assembly ("memory-safe") {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
53
dev/env/node_modules/@openzeppelin/contracts/utils/Blockhash.sol
generated
vendored
Executable file
53
dev/env/node_modules/@openzeppelin/contracts/utils/Blockhash.sol
generated
vendored
Executable file
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Blockhash.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Library for accessing historical block hashes beyond the standard 256 block limit.
|
||||
* Uses EIP-2935's history storage contract which maintains a ring buffer of the last
|
||||
* 8191 block hashes in state.
|
||||
*
|
||||
* For blocks within the last 256 blocks, it uses the native `BLOCKHASH` opcode.
|
||||
* For blocks between 257 and 8191 blocks ago, it queries the EIP-2935 history storage.
|
||||
* For blocks older than 8191 or future blocks, it returns zero, matching the `BLOCKHASH` behavior.
|
||||
*
|
||||
* NOTE: After EIP-2935 activation, it takes 8191 blocks to completely fill the history.
|
||||
* Before that, only block hashes since the fork block will be available.
|
||||
*/
|
||||
library Blockhash {
|
||||
/// @dev Address of the EIP-2935 history storage contract.
|
||||
address internal constant HISTORY_STORAGE_ADDRESS = 0x0000F90827F1C53a10cb7A02335B175320002935;
|
||||
|
||||
/**
|
||||
* @dev Retrieves the block hash for any historical block within the supported range.
|
||||
*
|
||||
* NOTE: The function gracefully handles future blocks and blocks beyond the history window
|
||||
* by returning zero, consistent with the EVM's native `BLOCKHASH` behavior.
|
||||
*/
|
||||
function blockHash(uint256 blockNumber) internal view returns (bytes32) {
|
||||
uint256 current = block.number;
|
||||
uint256 distance;
|
||||
|
||||
unchecked {
|
||||
// Can only wrap around to `current + 1` given `block.number - (2**256 - 1) = block.number + 1`
|
||||
distance = current - blockNumber;
|
||||
}
|
||||
|
||||
return distance < 257 ? blockhash(blockNumber) : _historyStorageCall(blockNumber);
|
||||
}
|
||||
|
||||
/// @dev Internal function to query the EIP-2935 history storage contract.
|
||||
function _historyStorageCall(uint256 blockNumber) private view returns (bytes32 hash) {
|
||||
assembly ("memory-safe") {
|
||||
// Store the blockNumber in scratch space
|
||||
mstore(0x00, blockNumber)
|
||||
mstore(0x20, 0)
|
||||
|
||||
// call history storage address
|
||||
pop(staticcall(gas(), HISTORY_STORAGE_ADDRESS, 0x00, 0x20, 0x20, 0x20))
|
||||
|
||||
// load result
|
||||
hash := mload(0x20)
|
||||
}
|
||||
}
|
||||
}
|
||||
113
dev/env/node_modules/@openzeppelin/contracts/utils/Bytes.sol
generated
vendored
Executable file
113
dev/env/node_modules/@openzeppelin/contracts/utils/Bytes.sol
generated
vendored
Executable file
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Bytes.sol)
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Math} from "./math/Math.sol";
|
||||
|
||||
/**
|
||||
* @dev Bytes operations.
|
||||
*/
|
||||
library Bytes {
|
||||
/**
|
||||
* @dev Forward search for `s` in `buffer`
|
||||
* * If `s` is present in the buffer, returns the index of the first instance
|
||||
* * If `s` is not present in the buffer, returns type(uint256).max
|
||||
*
|
||||
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]
|
||||
*/
|
||||
function indexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {
|
||||
return indexOf(buffer, s, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Forward search for `s` in `buffer` starting at position `pos`
|
||||
* * If `s` is present in the buffer (at or after `pos`), returns the index of the next instance
|
||||
* * If `s` is not present in the buffer (at or after `pos`), returns type(uint256).max
|
||||
*
|
||||
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]
|
||||
*/
|
||||
function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {
|
||||
uint256 length = buffer.length;
|
||||
for (uint256 i = pos; i < length; ++i) {
|
||||
if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return type(uint256).max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Backward search for `s` in `buffer`
|
||||
* * If `s` is present in the buffer, returns the index of the last instance
|
||||
* * If `s` is not present in the buffer, returns type(uint256).max
|
||||
*
|
||||
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`]
|
||||
*/
|
||||
function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {
|
||||
return lastIndexOf(buffer, s, type(uint256).max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Backward search for `s` in `buffer` starting at position `pos`
|
||||
* * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance
|
||||
* * If `s` is not present in the buffer (at or before `pos`), returns type(uint256).max
|
||||
*
|
||||
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`]
|
||||
*/
|
||||
function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {
|
||||
unchecked {
|
||||
uint256 length = buffer.length;
|
||||
for (uint256 i = Math.min(Math.saturatingAdd(pos, 1), length); i > 0; --i) {
|
||||
if (bytes1(_unsafeReadBytesOffset(buffer, i - 1)) == s) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return type(uint256).max;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Copies the content of `buffer`, from `start` (included) to the end of `buffer` into a new bytes object in
|
||||
* memory.
|
||||
*
|
||||
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
|
||||
*/
|
||||
function slice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {
|
||||
return slice(buffer, start, buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Copies the content of `buffer`, from `start` (included) to `end` (excluded) into a new bytes object in
|
||||
* memory.
|
||||
*
|
||||
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
|
||||
*/
|
||||
function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {
|
||||
// sanitize
|
||||
uint256 length = buffer.length;
|
||||
end = Math.min(end, length);
|
||||
start = Math.min(start, end);
|
||||
|
||||
// allocate and copy
|
||||
bytes memory result = new bytes(end - start);
|
||||
assembly ("memory-safe") {
|
||||
mcopy(add(result, 0x20), add(add(buffer, 0x20), start), sub(end, start))
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Reads a bytes32 from a bytes array without bounds checking.
|
||||
*
|
||||
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
|
||||
* assembly block as such would prevent some optimizations.
|
||||
*/
|
||||
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
|
||||
// This is not memory safe in the general case, but all calls to this private function are within bounds.
|
||||
assembly ("memory-safe") {
|
||||
value := mload(add(add(buffer, 0x20), offset))
|
||||
}
|
||||
}
|
||||
}
|
||||
54
dev/env/node_modules/@openzeppelin/contracts/utils/CAIP10.sol
generated
vendored
Executable file
54
dev/env/node_modules/@openzeppelin/contracts/utils/CAIP10.sol
generated
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.2.0) (utils/CAIP10.sol)
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Bytes} from "./Bytes.sol";
|
||||
import {Strings} from "./Strings.sol";
|
||||
import {CAIP2} from "./CAIP2.sol";
|
||||
|
||||
/**
|
||||
* @dev Helper library to format and parse CAIP-10 identifiers
|
||||
*
|
||||
* https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md[CAIP-10] defines account identifiers as:
|
||||
* account_id: chain_id + ":" + account_address
|
||||
* chain_id: [-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32} (See {CAIP2})
|
||||
* account_address: [-.%a-zA-Z0-9]{1,128}
|
||||
*
|
||||
* WARNING: According to [CAIP-10's canonicalization section](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md#canonicalization),
|
||||
* the implementation remains at the developer's discretion. Please note that case variations may introduce ambiguity.
|
||||
* For example, when building hashes to identify accounts or data associated to them, multiple representations of the
|
||||
* same account would derive to different hashes. For EVM chains, we recommend using checksummed addresses for the
|
||||
* "account_address" part. They can be generated onchain using {Strings-toChecksumHexString}.
|
||||
*/
|
||||
library CAIP10 {
|
||||
using Strings for address;
|
||||
using Bytes for bytes;
|
||||
|
||||
/// @dev Return the CAIP-10 identifier for an account on the current (local) chain.
|
||||
function local(address account) internal view returns (string memory) {
|
||||
return format(CAIP2.local(), account.toChecksumHexString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the CAIP-10 identifier for a given caip2 chain and account.
|
||||
*
|
||||
* NOTE: This function does not verify that the inputs are properly formatted.
|
||||
*/
|
||||
function format(string memory caip2, string memory account) internal pure returns (string memory) {
|
||||
return string.concat(caip2, ":", account);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse a CAIP-10 identifier into its components.
|
||||
*
|
||||
* NOTE: This function does not verify that the CAIP-10 input is properly formatted. The `caip2` return can be
|
||||
* parsed using the {CAIP2} library.
|
||||
*/
|
||||
function parse(string memory caip10) internal pure returns (string memory caip2, string memory account) {
|
||||
bytes memory buffer = bytes(caip10);
|
||||
|
||||
uint256 pos = buffer.lastIndexOf(":");
|
||||
return (string(buffer.slice(0, pos)), string(buffer.slice(pos + 1)));
|
||||
}
|
||||
}
|
||||
51
dev/env/node_modules/@openzeppelin/contracts/utils/CAIP2.sol
generated
vendored
Executable file
51
dev/env/node_modules/@openzeppelin/contracts/utils/CAIP2.sol
generated
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.2.0) (utils/CAIP2.sol)
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Bytes} from "./Bytes.sol";
|
||||
import {Strings} from "./Strings.sol";
|
||||
|
||||
/**
|
||||
* @dev Helper library to format and parse CAIP-2 identifiers
|
||||
*
|
||||
* https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md[CAIP-2] defines chain identifiers as:
|
||||
* chain_id: namespace + ":" + reference
|
||||
* namespace: [-a-z0-9]{3,8}
|
||||
* reference: [-_a-zA-Z0-9]{1,32}
|
||||
*
|
||||
* WARNING: In some cases, multiple CAIP-2 identifiers may all be valid representation of a single chain.
|
||||
* For EVM chains, it is recommended to use `eip155:xxx` as the canonical representation (where `xxx` is
|
||||
* the EIP-155 chain id). Consider the possible ambiguity when processing CAIP-2 identifiers or when using them
|
||||
* in the context of hashes.
|
||||
*/
|
||||
library CAIP2 {
|
||||
using Strings for uint256;
|
||||
using Bytes for bytes;
|
||||
|
||||
/// @dev Return the CAIP-2 identifier for the current (local) chain.
|
||||
function local() internal view returns (string memory) {
|
||||
return format("eip155", block.chainid.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the CAIP-2 identifier for a given namespace and reference.
|
||||
*
|
||||
* NOTE: This function does not verify that the inputs are properly formatted.
|
||||
*/
|
||||
function format(string memory namespace, string memory ref) internal pure returns (string memory) {
|
||||
return string.concat(namespace, ":", ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse a CAIP-2 identifier into its components.
|
||||
*
|
||||
* NOTE: This function does not verify that the CAIP-2 input is properly formatted.
|
||||
*/
|
||||
function parse(string memory caip2) internal pure returns (string memory namespace, string memory ref) {
|
||||
bytes memory buffer = bytes(caip2);
|
||||
|
||||
uint256 pos = buffer.indexOf(":");
|
||||
return (string(buffer.slice(0, pos)), string(buffer.slice(pos + 1)));
|
||||
}
|
||||
}
|
||||
25
dev/env/node_modules/@openzeppelin/contracts/utils/Calldata.sol
generated
vendored
Executable file
25
dev/env/node_modules/@openzeppelin/contracts/utils/Calldata.sol
generated
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Calldata.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Helper library for manipulating objects in calldata.
|
||||
*/
|
||||
library Calldata {
|
||||
// slither-disable-next-line write-after-write
|
||||
function emptyBytes() internal pure returns (bytes calldata result) {
|
||||
assembly ("memory-safe") {
|
||||
result.offset := 0
|
||||
result.length := 0
|
||||
}
|
||||
}
|
||||
|
||||
// slither-disable-next-line write-after-write
|
||||
function emptyString() internal pure returns (string calldata result) {
|
||||
assembly ("memory-safe") {
|
||||
result.offset := 0
|
||||
result.length := 0
|
||||
}
|
||||
}
|
||||
}
|
||||
19
dev/env/node_modules/@openzeppelin/contracts/utils/Comparators.sol
generated
vendored
Executable file
19
dev/env/node_modules/@openzeppelin/contracts/utils/Comparators.sol
generated
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Provides a set of functions to compare values.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library Comparators {
|
||||
function lt(uint256 a, uint256 b) internal pure returns (bool) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
function gt(uint256 a, uint256 b) internal pure returns (bool) {
|
||||
return a > b;
|
||||
}
|
||||
}
|
||||
28
dev/env/node_modules/@openzeppelin/contracts/utils/Context.sol
generated
vendored
Executable file
28
dev/env/node_modules/@openzeppelin/contracts/utils/Context.sol
generated
vendored
Executable 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;
|
||||
}
|
||||
}
|
||||
92
dev/env/node_modules/@openzeppelin/contracts/utils/Create2.sol
generated
vendored
Executable file
92
dev/env/node_modules/@openzeppelin/contracts/utils/Create2.sol
generated
vendored
Executable file
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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();
|
||||
}
|
||||
assembly ("memory-safe") {
|
||||
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
|
||||
// if no address was created, and returndata is not empty, bubble revert
|
||||
if and(iszero(addr), not(iszero(returndatasize()))) {
|
||||
let p := mload(0x40)
|
||||
returndatacopy(p, 0, returndatasize())
|
||||
revert(p, returndatasize())
|
||||
}
|
||||
}
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
34
dev/env/node_modules/@openzeppelin/contracts/utils/Errors.sol
generated
vendored
Executable file
34
dev/env/node_modules/@openzeppelin/contracts/utils/Errors.sol
generated
vendored
Executable file
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
|
||||
|
||||
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.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* @dev A necessary precompile is missing.
|
||||
*/
|
||||
error MissingPrecompile(address);
|
||||
}
|
||||
37
dev/env/node_modules/@openzeppelin/contracts/utils/Multicall.sol
generated
vendored
Executable file
37
dev/env/node_modules/@openzeppelin/contracts/utils/Multicall.sol
generated
vendored
Executable file
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (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 {Context-_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
|
||||
* {Context-_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
dev/env/node_modules/@openzeppelin/contracts/utils/Nonces.sol
generated
vendored
Executable file
46
dev/env/node_modules/@openzeppelin/contracts/utils/Nonces.sol
generated
vendored
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
dev/env/node_modules/@openzeppelin/contracts/utils/NoncesKeyed.sol
generated
vendored
Executable file
74
dev/env/node_modules/@openzeppelin/contracts/utils/NoncesKeyed.sol
generated
vendored
Executable file
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.2.0) (utils/NoncesKeyed.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Nonces} from "./Nonces.sol";
|
||||
|
||||
/**
|
||||
* @dev Alternative to {Nonces}, that supports key-ed nonces.
|
||||
*
|
||||
* Follows the https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337's semi-abstracted nonce system].
|
||||
*
|
||||
* NOTE: This contract inherits from {Nonces} and reuses its storage for the first nonce key (i.e. `0`). This
|
||||
* makes upgrading from {Nonces} to {NoncesKeyed} safe when using their upgradeable versions (e.g. `NoncesKeyedUpgradeable`).
|
||||
* Doing so will NOT reset the current state of nonces, avoiding replay attacks where a nonce is reused after the upgrade.
|
||||
*/
|
||||
abstract contract NoncesKeyed is Nonces {
|
||||
mapping(address owner => mapping(uint192 key => uint64)) private _nonces;
|
||||
|
||||
/// @dev Returns the next unused nonce for an address and key. Result contains the key prefix.
|
||||
function nonces(address owner, uint192 key) public view virtual returns (uint256) {
|
||||
return key == 0 ? nonces(owner) : _pack(key, _nonces[owner][key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Consumes the next unused nonce for an address and key.
|
||||
*
|
||||
* Returns the current value without the key prefix. Consumed nonce is increased, so calling this function twice
|
||||
* with the same arguments will return different (sequential) results.
|
||||
*/
|
||||
function _useNonce(address owner, uint192 key) 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 key == 0 ? _useNonce(owner) : _pack(key, _nonces[owner][key]++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
|
||||
*
|
||||
* This version takes the key and the nonce in a single uint256 parameter:
|
||||
* - use the first 24 bytes for the key
|
||||
* - use the last 8 bytes for the nonce
|
||||
*/
|
||||
function _useCheckedNonce(address owner, uint256 keyNonce) internal virtual override {
|
||||
(uint192 key, ) = _unpack(keyNonce);
|
||||
if (key == 0) {
|
||||
super._useCheckedNonce(owner, keyNonce);
|
||||
} else {
|
||||
uint256 current = _useNonce(owner, key);
|
||||
if (keyNonce != current) revert InvalidAccountNonce(owner, current);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
|
||||
*
|
||||
* This version takes the key and the nonce as two different parameters.
|
||||
*/
|
||||
function _useCheckedNonce(address owner, uint192 key, uint64 nonce) internal virtual {
|
||||
_useCheckedNonce(owner, _pack(key, nonce));
|
||||
}
|
||||
|
||||
/// @dev Pack key and nonce into a keyNonce
|
||||
function _pack(uint192 key, uint64 nonce) private pure returns (uint256) {
|
||||
return (uint256(key) << 64) | nonce;
|
||||
}
|
||||
|
||||
/// @dev Unpack a keyNonce into its key and nonce components
|
||||
function _unpack(uint256 keyNonce) private pure returns (uint192 key, uint64 nonce) {
|
||||
return (uint192(keyNonce >> 64), uint64(keyNonce));
|
||||
}
|
||||
}
|
||||
1656
dev/env/node_modules/@openzeppelin/contracts/utils/Packing.sol
generated
vendored
Executable file
1656
dev/env/node_modules/@openzeppelin/contracts/utils/Packing.sol
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
57
dev/env/node_modules/@openzeppelin/contracts/utils/Panic.sol
generated
vendored
Executable file
57
dev/env/node_modules/@openzeppelin/contracts/utils/Panic.sol
generated
vendored
Executable file
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
|
||||
|
||||
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].
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
// 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 {
|
||||
assembly ("memory-safe") {
|
||||
mstore(0x00, 0x4e487b71)
|
||||
mstore(0x20, code)
|
||||
revert(0x1c, 0x24)
|
||||
}
|
||||
}
|
||||
}
|
||||
112
dev/env/node_modules/@openzeppelin/contracts/utils/Pausable.sol
generated
vendored
Executable file
112
dev/env/node_modules/@openzeppelin/contracts/utils/Pausable.sol
generated
vendored
Executable file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.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 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());
|
||||
}
|
||||
}
|
||||
87
dev/env/node_modules/@openzeppelin/contracts/utils/ReentrancyGuard.sol
generated
vendored
Executable file
87
dev/env/node_modules/@openzeppelin/contracts/utils/ReentrancyGuard.sol
generated
vendored
Executable file
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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;
|
||||
}
|
||||
}
|
||||
61
dev/env/node_modules/@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol
generated
vendored
Executable file
61
dev/env/node_modules/@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol
generated
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol)
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {TransientSlot} from "./TransientSlot.sol";
|
||||
|
||||
/**
|
||||
* @dev Variant of {ReentrancyGuard} that uses transient storage.
|
||||
*
|
||||
* NOTE: This variant only works on networks where EIP-1153 is available.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
abstract contract ReentrancyGuardTransient {
|
||||
using TransientSlot 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, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
|
||||
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();
|
||||
}
|
||||
}
|
||||
122
dev/env/node_modules/@openzeppelin/contracts/utils/ShortStrings.sol
generated
vendored
Executable file
122
dev/env/node_modules/@openzeppelin/contracts/utils/ShortStrings.sol
generated
vendored
Executable file
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.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);
|
||||
assembly ("memory-safe") {
|
||||
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 {toShortStringWithFallback}.
|
||||
*/
|
||||
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
|
||||
* {toShortStringWithFallback}.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
dev/env/node_modules/@openzeppelin/contracts/utils/SlotDerivation.sol
generated
vendored
Executable file
155
dev/env/node_modules/@openzeppelin/contracts/utils/SlotDerivation.sol
generated
vendored
Executable file
@@ -0,0 +1,155 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)
|
||||
// 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.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library SlotDerivation {
|
||||
/**
|
||||
* @dev Derive an ERC-7201 slot from a string (namespace).
|
||||
*/
|
||||
function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
mstore(0x00, and(key, shr(96, not(0))))
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
mstore(0x00, iszero(iszero(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) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
143
dev/env/node_modules/@openzeppelin/contracts/utils/StorageSlot.sol
generated
vendored
Executable file
143
dev/env/node_modules/@openzeppelin/contracts/utils/StorageSlot.sol
generated
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 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) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a `StringSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := store.slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
|
||||
*/
|
||||
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
|
||||
assembly ("memory-safe") {
|
||||
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) {
|
||||
assembly ("memory-safe") {
|
||||
r.slot := store.slot
|
||||
}
|
||||
}
|
||||
}
|
||||
490
dev/env/node_modules/@openzeppelin/contracts/utils/Strings.sol
generated
vendored
Executable file
490
dev/env/node_modules/@openzeppelin/contracts/utils/Strings.sol
generated
vendored
Executable file
@@ -0,0 +1,490 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Strings.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "./math/Math.sol";
|
||||
import {SafeCast} from "./math/SafeCast.sol";
|
||||
import {SignedMath} from "./math/SignedMath.sol";
|
||||
|
||||
/**
|
||||
* @dev String operations.
|
||||
*/
|
||||
library Strings {
|
||||
using SafeCast for *;
|
||||
|
||||
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
|
||||
uint8 private constant ADDRESS_LENGTH = 20;
|
||||
uint256 private constant SPECIAL_CHARS_LOOKUP =
|
||||
(1 << 0x08) | // backspace
|
||||
(1 << 0x09) | // tab
|
||||
(1 << 0x0a) | // newline
|
||||
(1 << 0x0c) | // form feed
|
||||
(1 << 0x0d) | // carriage return
|
||||
(1 << 0x22) | // double quote
|
||||
(1 << 0x5c); // backslash
|
||||
|
||||
/**
|
||||
* @dev The `value` string doesn't fit in the specified `length`.
|
||||
*/
|
||||
error StringsInsufficientHexLength(uint256 value, uint256 length);
|
||||
|
||||
/**
|
||||
* @dev The string being parsed contains characters that are not in scope of the given base.
|
||||
*/
|
||||
error StringsInvalidChar();
|
||||
|
||||
/**
|
||||
* @dev The string being parsed is not a properly formatted address.
|
||||
*/
|
||||
error StringsInvalidAddressFormat();
|
||||
|
||||
/**
|
||||
* @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;
|
||||
assembly ("memory-safe") {
|
||||
ptr := add(add(buffer, 0x20), length)
|
||||
}
|
||||
while (true) {
|
||||
ptr--;
|
||||
assembly ("memory-safe") {
|
||||
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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
|
||||
* representation, according to EIP-55.
|
||||
*/
|
||||
function toChecksumHexString(address addr) internal pure returns (string memory) {
|
||||
bytes memory buffer = bytes(toHexString(addr));
|
||||
|
||||
// hash the hex part of buffer (skip length + 2 bytes, length 40)
|
||||
uint256 hashValue;
|
||||
assembly ("memory-safe") {
|
||||
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
|
||||
}
|
||||
|
||||
for (uint256 i = 41; i > 1; --i) {
|
||||
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
|
||||
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
|
||||
// case shift by xoring with 0x20
|
||||
buffer[i] ^= 0x20;
|
||||
}
|
||||
hashValue >>= 4;
|
||||
}
|
||||
return string(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse a decimal string and returns the value as a `uint256`.
|
||||
*
|
||||
* Requirements:
|
||||
* - The string must be formatted as `[0-9]*`
|
||||
* - The result must fit into an `uint256` type
|
||||
*/
|
||||
function parseUint(string memory input) internal pure returns (uint256) {
|
||||
return parseUint(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and
|
||||
* `end` (excluded).
|
||||
*
|
||||
* Requirements:
|
||||
* - The substring must be formatted as `[0-9]*`
|
||||
* - The result must fit into an `uint256` type
|
||||
*/
|
||||
function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
|
||||
(bool success, uint256 value) = tryParseUint(input, begin, end);
|
||||
if (!success) revert StringsInvalidChar();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
|
||||
*
|
||||
* NOTE: This function will revert if the result does not fit in a `uint256`.
|
||||
*/
|
||||
function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
|
||||
return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
|
||||
* character.
|
||||
*
|
||||
* NOTE: This function will revert if the result does not fit in a `uint256`.
|
||||
*/
|
||||
function tryParseUint(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) internal pure returns (bool success, uint256 value) {
|
||||
if (end > bytes(input).length || begin > end) return (false, 0);
|
||||
return _tryParseUintUncheckedBounds(input, begin, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
|
||||
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
|
||||
*/
|
||||
function _tryParseUintUncheckedBounds(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) private pure returns (bool success, uint256 value) {
|
||||
bytes memory buffer = bytes(input);
|
||||
|
||||
uint256 result = 0;
|
||||
for (uint256 i = begin; i < end; ++i) {
|
||||
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
|
||||
if (chr > 9) return (false, 0);
|
||||
result *= 10;
|
||||
result += chr;
|
||||
}
|
||||
return (true, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse a decimal string and returns the value as a `int256`.
|
||||
*
|
||||
* Requirements:
|
||||
* - The string must be formatted as `[-+]?[0-9]*`
|
||||
* - The result must fit in an `int256` type.
|
||||
*/
|
||||
function parseInt(string memory input) internal pure returns (int256) {
|
||||
return parseInt(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
|
||||
* `end` (excluded).
|
||||
*
|
||||
* Requirements:
|
||||
* - The substring must be formatted as `[-+]?[0-9]*`
|
||||
* - The result must fit in an `int256` type.
|
||||
*/
|
||||
function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
|
||||
(bool success, int256 value) = tryParseInt(input, begin, end);
|
||||
if (!success) revert StringsInvalidChar();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
|
||||
* the result does not fit in a `int256`.
|
||||
*
|
||||
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
|
||||
*/
|
||||
function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
|
||||
return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
uint256 private constant ABS_MIN_INT256 = 2 ** 255;
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
|
||||
* character or if the result does not fit in a `int256`.
|
||||
*
|
||||
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
|
||||
*/
|
||||
function tryParseInt(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) internal pure returns (bool success, int256 value) {
|
||||
if (end > bytes(input).length || begin > end) return (false, 0);
|
||||
return _tryParseIntUncheckedBounds(input, begin, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that
|
||||
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
|
||||
*/
|
||||
function _tryParseIntUncheckedBounds(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) private pure returns (bool success, int256 value) {
|
||||
bytes memory buffer = bytes(input);
|
||||
|
||||
// Check presence of a negative sign.
|
||||
bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
|
||||
bool positiveSign = sign == bytes1("+");
|
||||
bool negativeSign = sign == bytes1("-");
|
||||
uint256 offset = (positiveSign || negativeSign).toUint();
|
||||
|
||||
(bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
|
||||
|
||||
if (absSuccess && absValue < ABS_MIN_INT256) {
|
||||
return (true, negativeSign ? -int256(absValue) : int256(absValue));
|
||||
} else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
|
||||
return (true, type(int256).min);
|
||||
} else return (false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
|
||||
*
|
||||
* Requirements:
|
||||
* - The string must be formatted as `(0x)?[0-9a-fA-F]*`
|
||||
* - The result must fit in an `uint256` type.
|
||||
*/
|
||||
function parseHexUint(string memory input) internal pure returns (uint256) {
|
||||
return parseHexUint(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and
|
||||
* `end` (excluded).
|
||||
*
|
||||
* Requirements:
|
||||
* - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
|
||||
* - The result must fit in an `uint256` type.
|
||||
*/
|
||||
function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
|
||||
(bool success, uint256 value) = tryParseHexUint(input, begin, end);
|
||||
if (!success) revert StringsInvalidChar();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
|
||||
*
|
||||
* NOTE: This function will revert if the result does not fit in a `uint256`.
|
||||
*/
|
||||
function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
|
||||
return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
|
||||
* invalid character.
|
||||
*
|
||||
* NOTE: This function will revert if the result does not fit in a `uint256`.
|
||||
*/
|
||||
function tryParseHexUint(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) internal pure returns (bool success, uint256 value) {
|
||||
if (end > bytes(input).length || begin > end) return (false, 0);
|
||||
return _tryParseHexUintUncheckedBounds(input, begin, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
|
||||
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
|
||||
*/
|
||||
function _tryParseHexUintUncheckedBounds(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) private pure returns (bool success, uint256 value) {
|
||||
bytes memory buffer = bytes(input);
|
||||
|
||||
// skip 0x prefix if present
|
||||
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
|
||||
uint256 offset = hasPrefix.toUint() * 2;
|
||||
|
||||
uint256 result = 0;
|
||||
for (uint256 i = begin + offset; i < end; ++i) {
|
||||
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
|
||||
if (chr > 15) return (false, 0);
|
||||
result *= 16;
|
||||
unchecked {
|
||||
// Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
|
||||
// This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.
|
||||
result += chr;
|
||||
}
|
||||
}
|
||||
return (true, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
|
||||
*
|
||||
* Requirements:
|
||||
* - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
|
||||
*/
|
||||
function parseAddress(string memory input) internal pure returns (address) {
|
||||
return parseAddress(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and
|
||||
* `end` (excluded).
|
||||
*
|
||||
* Requirements:
|
||||
* - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
|
||||
*/
|
||||
function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
|
||||
(bool success, address value) = tryParseAddress(input, begin, end);
|
||||
if (!success) revert StringsInvalidAddressFormat();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
|
||||
* formatted address. See {parseAddress-string} requirements.
|
||||
*/
|
||||
function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
|
||||
return tryParseAddress(input, 0, bytes(input).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
|
||||
* formatted address. See {parseAddress-string-uint256-uint256} requirements.
|
||||
*/
|
||||
function tryParseAddress(
|
||||
string memory input,
|
||||
uint256 begin,
|
||||
uint256 end
|
||||
) internal pure returns (bool success, address value) {
|
||||
if (end > bytes(input).length || begin > end) return (false, address(0));
|
||||
|
||||
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
|
||||
uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
|
||||
|
||||
// check that input is the correct length
|
||||
if (end - begin == expectedLength) {
|
||||
// length guarantees that this does not overflow, and value is at most type(uint160).max
|
||||
(bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
|
||||
return (s, address(uint160(v)));
|
||||
} else {
|
||||
return (false, address(0));
|
||||
}
|
||||
}
|
||||
|
||||
function _tryParseChr(bytes1 chr) private pure returns (uint8) {
|
||||
uint8 value = uint8(chr);
|
||||
|
||||
// Try to parse `chr`:
|
||||
// - Case 1: [0-9]
|
||||
// - Case 2: [a-f]
|
||||
// - Case 3: [A-F]
|
||||
// - otherwise not supported
|
||||
unchecked {
|
||||
if (value > 47 && value < 58) value -= 48;
|
||||
else if (value > 96 && value < 103) value -= 87;
|
||||
else if (value > 64 && value < 71) value -= 55;
|
||||
else return type(uint8).max;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.
|
||||
*
|
||||
* WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.
|
||||
*
|
||||
* NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of
|
||||
* RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode
|
||||
* characters that are not in this range, but other tooling may provide different results.
|
||||
*/
|
||||
function escapeJSON(string memory input) internal pure returns (string memory) {
|
||||
bytes memory buffer = bytes(input);
|
||||
bytes memory output = new bytes(2 * buffer.length); // worst case scenario
|
||||
uint256 outputLength = 0;
|
||||
|
||||
for (uint256 i; i < buffer.length; ++i) {
|
||||
bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));
|
||||
if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {
|
||||
output[outputLength++] = "\\";
|
||||
if (char == 0x08) output[outputLength++] = "b";
|
||||
else if (char == 0x09) output[outputLength++] = "t";
|
||||
else if (char == 0x0a) output[outputLength++] = "n";
|
||||
else if (char == 0x0c) output[outputLength++] = "f";
|
||||
else if (char == 0x0d) output[outputLength++] = "r";
|
||||
else if (char == 0x5c) output[outputLength++] = "\\";
|
||||
else if (char == 0x22) {
|
||||
// solhint-disable-next-line quotes
|
||||
output[outputLength++] = '"';
|
||||
}
|
||||
} else {
|
||||
output[outputLength++] = char;
|
||||
}
|
||||
}
|
||||
// write the actual length and deallocate unused memory
|
||||
assembly ("memory-safe") {
|
||||
mstore(output, outputLength)
|
||||
mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))
|
||||
}
|
||||
|
||||
return string(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Reads a bytes32 from a bytes array without bounds checking.
|
||||
*
|
||||
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
|
||||
* assembly block as such would prevent some optimizations.
|
||||
*/
|
||||
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
|
||||
// This is not memory safe in the general case, but all calls to this private function are within bounds.
|
||||
assembly ("memory-safe") {
|
||||
value := mload(add(add(buffer, 0x20), offset))
|
||||
}
|
||||
}
|
||||
}
|
||||
183
dev/env/node_modules/@openzeppelin/contracts/utils/TransientSlot.sol
generated
vendored
Executable file
183
dev/env/node_modules/@openzeppelin/contracts/utils/TransientSlot.sol
generated
vendored
Executable file
@@ -0,0 +1,183 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/**
|
||||
* @dev Library for reading and writing value-types to specific transient storage slots.
|
||||
*
|
||||
* Transient slots are often used to store temporary values that are removed after the current transaction.
|
||||
* This library helps with reading and writing to such slots without the need for inline assembly.
|
||||
*
|
||||
* * Example reading and writing values using transient storage:
|
||||
* ```solidity
|
||||
* contract Lock {
|
||||
* using TransientSlot for *;
|
||||
*
|
||||
* // 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 TransientSlot {
|
||||
/**
|
||||
* @dev UDVT that represents a slot holding an address.
|
||||
*/
|
||||
type AddressSlot is bytes32;
|
||||
|
||||
/**
|
||||
* @dev Cast an arbitrary slot to a AddressSlot.
|
||||
*/
|
||||
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
|
||||
return AddressSlot.wrap(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev UDVT that represents a slot holding a bool.
|
||||
*/
|
||||
type BooleanSlot is bytes32;
|
||||
|
||||
/**
|
||||
* @dev Cast an arbitrary slot to a BooleanSlot.
|
||||
*/
|
||||
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
|
||||
return BooleanSlot.wrap(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev UDVT that represents a slot holding a bytes32.
|
||||
*/
|
||||
type Bytes32Slot is bytes32;
|
||||
|
||||
/**
|
||||
* @dev Cast an arbitrary slot to a Bytes32Slot.
|
||||
*/
|
||||
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
|
||||
return Bytes32Slot.wrap(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev UDVT that represents a slot holding a uint256.
|
||||
*/
|
||||
type Uint256Slot is bytes32;
|
||||
|
||||
/**
|
||||
* @dev Cast an arbitrary slot to a Uint256Slot.
|
||||
*/
|
||||
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
|
||||
return Uint256Slot.wrap(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev UDVT that represents a slot holding a int256.
|
||||
*/
|
||||
type Int256Slot is bytes32;
|
||||
|
||||
/**
|
||||
* @dev Cast an arbitrary slot to a Int256Slot.
|
||||
*/
|
||||
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
|
||||
return Int256Slot.wrap(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(AddressSlot slot) internal view returns (address value) {
|
||||
assembly ("memory-safe") {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(AddressSlot slot, address value) internal {
|
||||
assembly ("memory-safe") {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(BooleanSlot slot) internal view returns (bool value) {
|
||||
assembly ("memory-safe") {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(BooleanSlot slot, bool value) internal {
|
||||
assembly ("memory-safe") {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
|
||||
assembly ("memory-safe") {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(Bytes32Slot slot, bytes32 value) internal {
|
||||
assembly ("memory-safe") {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(Uint256Slot slot) internal view returns (uint256 value) {
|
||||
assembly ("memory-safe") {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(Uint256Slot slot, uint256 value) internal {
|
||||
assembly ("memory-safe") {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Load the value held at location `slot` in transient storage.
|
||||
*/
|
||||
function tload(Int256Slot slot) internal view returns (int256 value) {
|
||||
assembly ("memory-safe") {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store `value` at location `slot` in transient storage.
|
||||
*/
|
||||
function tstore(Int256Slot slot, int256 value) internal {
|
||||
assembly ("memory-safe") {
|
||||
tstore(slot, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
180
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol
generated
vendored
Executable file
180
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol
generated
vendored
Executable file
@@ -0,0 +1,180 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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 recovered, RecoverError err, bytes32 errArg) {
|
||||
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.
|
||||
assembly ("memory-safe") {
|
||||
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 recovered, RecoverError err, bytes32 errArg) {
|
||||
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 recovered, RecoverError err, bytes32 errArg) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
160
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/EIP712.sol
generated
vendored
Executable file
160
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/EIP712.sol
generated
vendored
Executable file
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.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;
|
||||
// slither-disable-next-line constable-states
|
||||
string private _nameFallback;
|
||||
// slither-disable-next-line constable-states
|
||||
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);
|
||||
}
|
||||
|
||||
/// @inheritdoc IERC5267
|
||||
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);
|
||||
}
|
||||
}
|
||||
31
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/Hashes.sol
generated
vendored
Executable file
31
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/Hashes.sol
generated
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/Hashes.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Library of standard hash functions.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
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) internal pure returns (bytes32 value) {
|
||||
assembly ("memory-safe") {
|
||||
mstore(0x00, a)
|
||||
mstore(0x20, b)
|
||||
value := keccak256(0x00, 0x40)
|
||||
}
|
||||
}
|
||||
}
|
||||
514
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/MerkleProof.sol
generated
vendored
Executable file
514
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/MerkleProof.sol
generated
vendored
Executable file
@@ -0,0 +1,514 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/MerkleProof.js.
|
||||
|
||||
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.
|
||||
*
|
||||
* IMPORTANT: Consider memory side-effects when using custom hashing functions
|
||||
* that access memory in an unsafe way.
|
||||
*
|
||||
* NOTE: This library supports proof verification for merkle trees built using
|
||||
* custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving
|
||||
* leaf inclusion in trees built using non-commutative hashing functions requires
|
||||
* additional logic that is not supported by this library.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This version handles proofs in memory with the default hashing function.
|
||||
*/
|
||||
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
|
||||
return processProof(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 leaves & pre-images are assumed to be sorted.
|
||||
*
|
||||
* This version handles proofs in memory with the default hashing function.
|
||||
*/
|
||||
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 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.
|
||||
*
|
||||
* This version handles proofs in memory with a custom hashing function.
|
||||
*/
|
||||
function verify(
|
||||
bytes32[] memory proof,
|
||||
bytes32 root,
|
||||
bytes32 leaf,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view returns (bool) {
|
||||
return processProof(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted.
|
||||
*
|
||||
* This version handles proofs in memory with a custom hashing function.
|
||||
*/
|
||||
function processProof(
|
||||
bytes32[] memory proof,
|
||||
bytes32 leaf,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view returns (bytes32) {
|
||||
bytes32 computedHash = leaf;
|
||||
for (uint256 i = 0; i < proof.length; i++) {
|
||||
computedHash = hasher(computedHash, proof[i]);
|
||||
}
|
||||
return computedHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* This version handles proofs in calldata with the default hashing function.
|
||||
*/
|
||||
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 leaves & pre-images are assumed to be sorted.
|
||||
*
|
||||
* This version handles proofs in calldata with the default hashing function.
|
||||
*/
|
||||
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 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.
|
||||
*
|
||||
* This version handles proofs in calldata with a custom hashing function.
|
||||
*/
|
||||
function verifyCalldata(
|
||||
bytes32[] calldata proof,
|
||||
bytes32 root,
|
||||
bytes32 leaf,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view returns (bool) {
|
||||
return processProofCalldata(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted.
|
||||
*
|
||||
* This version handles proofs in calldata with a custom hashing function.
|
||||
*/
|
||||
function processProofCalldata(
|
||||
bytes32[] calldata proof,
|
||||
bytes32 leaf,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view returns (bytes32) {
|
||||
bytes32 computedHash = leaf;
|
||||
for (uint256 i = 0; i < proof.length; i++) {
|
||||
computedHash = hasher(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}.
|
||||
*
|
||||
* This version handles multiproofs in memory with the default hashing function.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*
|
||||
* NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
|
||||
* The `leaves` must be validated independently. See {processMultiProof}.
|
||||
*/
|
||||
function multiProofVerify(
|
||||
bytes32[] memory proof,
|
||||
bool[] memory proofFlags,
|
||||
bytes32 root,
|
||||
bytes32[] memory leaves
|
||||
) internal pure returns (bool) {
|
||||
return processMultiProof(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.
|
||||
*
|
||||
* This version handles multiproofs in memory with the default hashing function.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
|
||||
* and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
|
||||
* validating the leaves elsewhere.
|
||||
*/
|
||||
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 proofFlagsLen = proofFlags.length;
|
||||
|
||||
// Check proof validity.
|
||||
if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
|
||||
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 < proofFlagsLen; 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 (proofFlagsLen > 0) {
|
||||
if (proofPos != proof.length) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
unchecked {
|
||||
return hashes[proofFlagsLen - 1];
|
||||
}
|
||||
} else if (leavesLen > 0) {
|
||||
return leaves[0];
|
||||
} else {
|
||||
return proof[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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}.
|
||||
*
|
||||
* This version handles multiproofs in memory with a custom hashing function.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*
|
||||
* NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
|
||||
* The `leaves` must be validated independently. See {processMultiProof}.
|
||||
*/
|
||||
function multiProofVerify(
|
||||
bytes32[] memory proof,
|
||||
bool[] memory proofFlags,
|
||||
bytes32 root,
|
||||
bytes32[] memory leaves,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view returns (bool) {
|
||||
return processMultiProof(proof, proofFlags, leaves, hasher) == 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.
|
||||
*
|
||||
* This version handles multiproofs in memory with a custom hashing function.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
|
||||
* and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
|
||||
* validating the leaves elsewhere.
|
||||
*/
|
||||
function processMultiProof(
|
||||
bytes32[] memory proof,
|
||||
bool[] memory proofFlags,
|
||||
bytes32[] memory leaves,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view 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 proofFlagsLen = proofFlags.length;
|
||||
|
||||
// Check proof validity.
|
||||
if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
|
||||
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 < proofFlagsLen; i++) {
|
||||
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
|
||||
bytes32 b = proofFlags[i]
|
||||
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
|
||||
: proof[proofPos++];
|
||||
hashes[i] = hasher(a, b);
|
||||
}
|
||||
|
||||
if (proofFlagsLen > 0) {
|
||||
if (proofPos != proof.length) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
unchecked {
|
||||
return hashes[proofFlagsLen - 1];
|
||||
}
|
||||
} else if (leavesLen > 0) {
|
||||
return leaves[0];
|
||||
} else {
|
||||
return proof[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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}.
|
||||
*
|
||||
* This version handles multiproofs in calldata with the default hashing function.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*
|
||||
* NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
|
||||
* The `leaves` must be validated independently. See {processMultiProofCalldata}.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This version handles multiproofs in calldata with the default hashing function.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
|
||||
* and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
|
||||
* validating the leaves elsewhere.
|
||||
*/
|
||||
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 proofFlagsLen = proofFlags.length;
|
||||
|
||||
// Check proof validity.
|
||||
if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
|
||||
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 < proofFlagsLen; 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 (proofFlagsLen > 0) {
|
||||
if (proofPos != proof.length) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
unchecked {
|
||||
return hashes[proofFlagsLen - 1];
|
||||
}
|
||||
} else if (leavesLen > 0) {
|
||||
return leaves[0];
|
||||
} else {
|
||||
return proof[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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}.
|
||||
*
|
||||
* This version handles multiproofs in calldata with a custom hashing function.
|
||||
*
|
||||
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
|
||||
*
|
||||
* NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
|
||||
* The `leaves` must be validated independently. See {processMultiProofCalldata}.
|
||||
*/
|
||||
function multiProofVerifyCalldata(
|
||||
bytes32[] calldata proof,
|
||||
bool[] calldata proofFlags,
|
||||
bytes32 root,
|
||||
bytes32[] memory leaves,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view returns (bool) {
|
||||
return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == 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.
|
||||
*
|
||||
* This version handles multiproofs in calldata with a custom hashing function.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
|
||||
* and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
|
||||
* validating the leaves elsewhere.
|
||||
*/
|
||||
function processMultiProofCalldata(
|
||||
bytes32[] calldata proof,
|
||||
bool[] calldata proofFlags,
|
||||
bytes32[] memory leaves,
|
||||
function(bytes32, bytes32) view returns (bytes32) hasher
|
||||
) internal view 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 proofFlagsLen = proofFlags.length;
|
||||
|
||||
// Check proof validity.
|
||||
if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
|
||||
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 < proofFlagsLen; i++) {
|
||||
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
|
||||
bytes32 b = proofFlags[i]
|
||||
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
|
||||
: proof[proofPos++];
|
||||
hashes[i] = hasher(a, b);
|
||||
}
|
||||
|
||||
if (proofFlagsLen > 0) {
|
||||
if (proofPos != proof.length) {
|
||||
revert MerkleProofInvalidMultiproof();
|
||||
}
|
||||
unchecked {
|
||||
return hashes[proofFlagsLen - 1];
|
||||
}
|
||||
} else if (leavesLen > 0) {
|
||||
return leaves[0];
|
||||
} else {
|
||||
return proof[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
99
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol
generated
vendored
Executable file
99
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol
generated
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.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://ethereum.org/en/developers/docs/apis/json-rpc/#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) {
|
||||
assembly ("memory-safe") {
|
||||
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://ethereum.org/en/developers/docs/apis/json-rpc/#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 Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.
|
||||
*/
|
||||
function toDataWithIntendedValidatorHash(
|
||||
address validator,
|
||||
bytes32 messageHash
|
||||
) internal pure returns (bytes32 digest) {
|
||||
assembly ("memory-safe") {
|
||||
mstore(0x00, hex"19_00")
|
||||
mstore(0x02, shl(96, validator))
|
||||
mstore(0x16, messageHash)
|
||||
digest := keccak256(0x00, 0x36)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
assembly ("memory-safe") {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, hex"19_01")
|
||||
mstore(add(ptr, 0x02), domainSeparator)
|
||||
mstore(add(ptr, 0x22), structHash)
|
||||
digest := keccak256(ptr, 0x42)
|
||||
}
|
||||
}
|
||||
}
|
||||
408
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/P256.sol
generated
vendored
Executable file
408
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/P256.sol
generated
vendored
Executable file
@@ -0,0 +1,408 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/P256.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
import {Errors} from "../Errors.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of secp256r1 verification and recovery functions.
|
||||
*
|
||||
* The secp256r1 curve (also known as P256) is a NIST standard curve with wide support in modern devices
|
||||
* and cryptographic standards. Some notable examples include Apple's Secure Enclave and Android's Keystore
|
||||
* as well as authentication protocols like FIDO2.
|
||||
*
|
||||
* Based on the original https://github.com/itsobvioustech/aa-passkeys-wallet/blob/d3d423f28a4d8dfcb203c7fa0c47f42592a7378e/src/Secp256r1.sol[implementation of itsobvioustech] (GNU General Public License v3.0).
|
||||
* Heavily inspired in https://github.com/maxrobot/elliptic-solidity/blob/c4bb1b6e8ae89534d8db3a6b3a6b52219100520f/contracts/Secp256r1.sol[maxrobot] and
|
||||
* https://github.com/tdrerup/elliptic-curve-solidity/blob/59a9c25957d4d190eff53b6610731d81a077a15e/contracts/curves/EllipticCurve.sol[tdrerup] implementations.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library P256 {
|
||||
struct JPoint {
|
||||
uint256 x;
|
||||
uint256 y;
|
||||
uint256 z;
|
||||
}
|
||||
|
||||
/// @dev Generator (x component)
|
||||
uint256 internal constant GX = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296;
|
||||
/// @dev Generator (y component)
|
||||
uint256 internal constant GY = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5;
|
||||
/// @dev P (size of the field)
|
||||
uint256 internal constant P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
|
||||
/// @dev N (order of G)
|
||||
uint256 internal constant N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
|
||||
/// @dev A parameter of the weierstrass equation
|
||||
uint256 internal constant A = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC;
|
||||
/// @dev B parameter of the weierstrass equation
|
||||
uint256 internal constant B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;
|
||||
|
||||
/// @dev (P + 1) / 4. Useful to compute sqrt
|
||||
uint256 private constant P1DIV4 = 0x3fffffffc0000000400000000000000000000000400000000000000000000000;
|
||||
|
||||
/// @dev N/2 for excluding higher order `s` values
|
||||
uint256 private constant HALF_N = 0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8;
|
||||
|
||||
/**
|
||||
* @dev Verifies a secp256r1 signature using the RIP-7212 precompile and falls back to the Solidity implementation
|
||||
* if the precompile is not available. This version should work on all chains, but requires the deployment of more
|
||||
* bytecode.
|
||||
*
|
||||
* @param h - hashed message
|
||||
* @param r - signature half R
|
||||
* @param s - signature half S
|
||||
* @param qx - public key coordinate X
|
||||
* @param qy - public key coordinate Y
|
||||
*
|
||||
* IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability.
|
||||
* To flip the `s` value, compute `s = N - s`.
|
||||
*/
|
||||
function verify(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) {
|
||||
(bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy);
|
||||
return supported ? valid : verifySolidity(h, r, s, qx, qy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {verify}, but it will revert if the required precompile is not available.
|
||||
*
|
||||
* Make sure any logic (code or precompile) deployed at that address is the expected one,
|
||||
* otherwise the returned value may be misinterpreted as a positive boolean.
|
||||
*/
|
||||
function verifyNative(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) {
|
||||
(bool valid, bool supported) = _tryVerifyNative(h, r, s, qx, qy);
|
||||
if (supported) {
|
||||
return valid;
|
||||
} else {
|
||||
revert Errors.MissingPrecompile(address(0x100));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {verify}, but it will return false if the required precompile is not available.
|
||||
*/
|
||||
function _tryVerifyNative(
|
||||
bytes32 h,
|
||||
bytes32 r,
|
||||
bytes32 s,
|
||||
bytes32 qx,
|
||||
bytes32 qy
|
||||
) private view returns (bool valid, bool supported) {
|
||||
if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) {
|
||||
return (false, true); // signature is invalid, and its not because the precompile is missing
|
||||
} else if (_rip7212(h, r, s, qx, qy)) {
|
||||
return (true, true); // precompile is present, signature is valid
|
||||
} else if (
|
||||
// Given precompiles have no bytecode (i.e. `address(0x100).code.length == 0`), we use
|
||||
// a valid signature with small `r` and `s` values to check if the precompile is present. Taken from
|
||||
// https://github.com/C2SP/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/ecdsa_secp256r1_sha256_p1363_test.json#L1173-L1204
|
||||
_rip7212(
|
||||
0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023, // sha256("123400")
|
||||
0x0000000000000000000000000000000000000000000000000000000000000005,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000001,
|
||||
0xa71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957,
|
||||
0x5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b
|
||||
)
|
||||
) {
|
||||
return (false, true); // precompile is present, signature is invalid
|
||||
} else {
|
||||
return (false, false); // precompile is absent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Low level helper for {_tryVerifyNative}. Calls the precompile and checks if there is a return value.
|
||||
*/
|
||||
function _rip7212(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) private view returns (bool isValid) {
|
||||
assembly ("memory-safe") {
|
||||
// Use the free memory pointer without updating it at the end of the function
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, h)
|
||||
mstore(add(ptr, 0x20), r)
|
||||
mstore(add(ptr, 0x40), s)
|
||||
mstore(add(ptr, 0x60), qx)
|
||||
mstore(add(ptr, 0x80), qy)
|
||||
// RIP-7212 precompiles return empty bytes when an invalid signature is passed, making it impossible
|
||||
// to distinguish the presence of the precompile. Custom precompile implementations may decide to
|
||||
// return `bytes32(0)` (i.e. false) without developers noticing, so we decide to evaluate the return value
|
||||
// without expanding memory using scratch space.
|
||||
mstore(0x00, 0) // zero out scratch space in case the precompile doesn't return anything
|
||||
if iszero(staticcall(gas(), 0x100, ptr, 0xa0, 0x00, 0x20)) {
|
||||
invalid()
|
||||
}
|
||||
isValid := mload(0x00)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {verify}, but only the Solidity implementation is used.
|
||||
*/
|
||||
function verifySolidity(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) internal view returns (bool) {
|
||||
if (!_isProperSignature(r, s) || !isValidPublicKey(qx, qy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JPoint[16] memory points = _preComputeJacobianPoints(uint256(qx), uint256(qy));
|
||||
uint256 w = Math.invModPrime(uint256(s), N);
|
||||
uint256 u1 = mulmod(uint256(h), w, N);
|
||||
uint256 u2 = mulmod(uint256(r), w, N);
|
||||
(uint256 x, ) = _jMultShamir(points, u1, u2);
|
||||
return ((x % N) == uint256(r));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Public key recovery
|
||||
*
|
||||
* @param h - hashed message
|
||||
* @param v - signature recovery param
|
||||
* @param r - signature half R
|
||||
* @param s - signature half S
|
||||
*
|
||||
* IMPORTANT: This function disallows signatures where the `s` value is above `N/2` to prevent malleability.
|
||||
* To flip the `s` value, compute `s = N - s` and `v = 1 - v` if (`v = 0 | 1`).
|
||||
*/
|
||||
function recovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) internal view returns (bytes32 x, bytes32 y) {
|
||||
if (!_isProperSignature(r, s) || v > 1) {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
uint256 p = P; // cache P on the stack
|
||||
uint256 rx = uint256(r);
|
||||
uint256 ry2 = addmod(mulmod(addmod(mulmod(rx, rx, p), A, p), rx, p), B, p); // weierstrass equation y² = x³ + a.x + b
|
||||
uint256 ry = Math.modExp(ry2, P1DIV4, p); // This formula for sqrt work because P ≡ 3 (mod 4)
|
||||
if (mulmod(ry, ry, p) != ry2) return (0, 0); // Sanity check
|
||||
if (ry % 2 != v) ry = p - ry;
|
||||
|
||||
JPoint[16] memory points = _preComputeJacobianPoints(rx, ry);
|
||||
uint256 w = Math.invModPrime(uint256(r), N);
|
||||
uint256 u1 = mulmod(N - (uint256(h) % N), w, N);
|
||||
uint256 u2 = mulmod(uint256(s), w, N);
|
||||
(uint256 xU, uint256 yU) = _jMultShamir(points, u1, u2);
|
||||
return (bytes32(xU), bytes32(yU));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if (x, y) are valid coordinates of a point on the curve.
|
||||
* In particular this function checks that x < P and y < P.
|
||||
*/
|
||||
function isValidPublicKey(bytes32 x, bytes32 y) internal pure returns (bool result) {
|
||||
assembly ("memory-safe") {
|
||||
let p := P
|
||||
let lhs := mulmod(y, y, p) // y^2
|
||||
let rhs := addmod(mulmod(addmod(mulmod(x, x, p), A, p), x, p), B, p) // ((x^2 + a) * x) + b = x^3 + ax + b
|
||||
result := and(and(lt(x, p), lt(y, p)), eq(lhs, rhs)) // Should conform with the Weierstrass equation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if (r, s) is a proper signature.
|
||||
* In particular, this checks that `s` is in the "lower-range", making the signature non-malleable.
|
||||
*/
|
||||
function _isProperSignature(bytes32 r, bytes32 s) private pure returns (bool) {
|
||||
return uint256(r) > 0 && uint256(r) < N && uint256(s) > 0 && uint256(s) <= HALF_N;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Reduce from jacobian to affine coordinates
|
||||
* @param jx - jacobian coordinate x
|
||||
* @param jy - jacobian coordinate y
|
||||
* @param jz - jacobian coordinate z
|
||||
* @return ax - affine coordinate x
|
||||
* @return ay - affine coordinate y
|
||||
*/
|
||||
function _affineFromJacobian(uint256 jx, uint256 jy, uint256 jz) private view returns (uint256 ax, uint256 ay) {
|
||||
if (jz == 0) return (0, 0);
|
||||
uint256 p = P; // cache P on the stack
|
||||
uint256 zinv = Math.invModPrime(jz, p);
|
||||
assembly ("memory-safe") {
|
||||
let zzinv := mulmod(zinv, zinv, p)
|
||||
ax := mulmod(jx, zzinv, p)
|
||||
ay := mulmod(jy, mulmod(zzinv, zinv, p), p)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Point addition on the jacobian coordinates
|
||||
* Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-1998-cmo-2
|
||||
*
|
||||
* Note that:
|
||||
*
|
||||
* - `addition-add-1998-cmo-2` doesn't support identical input points. This version is modified to use
|
||||
* the `h` and `r` values computed by `addition-add-1998-cmo-2` to detect identical inputs, and fallback to
|
||||
* `doubling-dbl-1998-cmo-2` if needed.
|
||||
* - if one of the points is at infinity (i.e. `z=0`), the result is undefined.
|
||||
*/
|
||||
function _jAdd(
|
||||
JPoint memory p1,
|
||||
uint256 x2,
|
||||
uint256 y2,
|
||||
uint256 z2
|
||||
) private pure returns (uint256 rx, uint256 ry, uint256 rz) {
|
||||
assembly ("memory-safe") {
|
||||
let p := P
|
||||
let z1 := mload(add(p1, 0x40))
|
||||
let zz1 := mulmod(z1, z1, p) // zz1 = z1²
|
||||
let s1 := mulmod(mload(add(p1, 0x20)), mulmod(mulmod(z2, z2, p), z2, p), p) // s1 = y1*z2³
|
||||
let r := addmod(mulmod(y2, mulmod(zz1, z1, p), p), sub(p, s1), p) // r = s2-s1 = y2*z1³-s1 = y2*z1³-y1*z2³
|
||||
let u1 := mulmod(mload(p1), mulmod(z2, z2, p), p) // u1 = x1*z2²
|
||||
let h := addmod(mulmod(x2, zz1, p), sub(p, u1), p) // h = u2-u1 = x2*z1²-u1 = x2*z1²-x1*z2²
|
||||
|
||||
// detect edge cases where inputs are identical
|
||||
switch and(iszero(r), iszero(h))
|
||||
// case 0: points are different
|
||||
case 0 {
|
||||
let hh := mulmod(h, h, p) // h²
|
||||
|
||||
// x' = r²-h³-2*u1*h²
|
||||
rx := addmod(
|
||||
addmod(mulmod(r, r, p), sub(p, mulmod(h, hh, p)), p),
|
||||
sub(p, mulmod(2, mulmod(u1, hh, p), p)),
|
||||
p
|
||||
)
|
||||
// y' = r*(u1*h²-x')-s1*h³
|
||||
ry := addmod(
|
||||
mulmod(r, addmod(mulmod(u1, hh, p), sub(p, rx), p), p),
|
||||
sub(p, mulmod(s1, mulmod(h, hh, p), p)),
|
||||
p
|
||||
)
|
||||
// z' = h*z1*z2
|
||||
rz := mulmod(h, mulmod(z1, z2, p), p)
|
||||
}
|
||||
// case 1: points are equal
|
||||
case 1 {
|
||||
let x := x2
|
||||
let y := y2
|
||||
let z := z2
|
||||
let yy := mulmod(y, y, p)
|
||||
let zz := mulmod(z, z, p)
|
||||
let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴
|
||||
let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y²
|
||||
|
||||
// x' = t = m²-2*s
|
||||
rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)
|
||||
|
||||
// y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴
|
||||
// cut the computation to avoid stack too deep
|
||||
let rytmp1 := sub(p, mulmod(8, mulmod(yy, yy, p), p)) // -8*y⁴
|
||||
let rytmp2 := addmod(s, sub(p, rx), p) // s-x'
|
||||
ry := addmod(mulmod(m, rytmp2, p), rytmp1, p) // m*(s-x')-8*y⁴
|
||||
|
||||
// z' = 2*y*z
|
||||
rz := mulmod(2, mulmod(y, z, p), p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Point doubling on the jacobian coordinates
|
||||
* Reference: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2
|
||||
*/
|
||||
function _jDouble(uint256 x, uint256 y, uint256 z) private pure returns (uint256 rx, uint256 ry, uint256 rz) {
|
||||
assembly ("memory-safe") {
|
||||
let p := P
|
||||
let yy := mulmod(y, y, p)
|
||||
let zz := mulmod(z, z, p)
|
||||
let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(A, mulmod(zz, zz, p), p), p) // m = 3*x²+a*z⁴
|
||||
let s := mulmod(4, mulmod(x, yy, p), p) // s = 4*x*y²
|
||||
|
||||
// x' = t = m²-2*s
|
||||
rx := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)
|
||||
// y' = m*(s-t)-8*y⁴ = m*(s-x')-8*y⁴
|
||||
ry := addmod(mulmod(m, addmod(s, sub(p, rx), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)
|
||||
// z' = 2*y*z
|
||||
rz := mulmod(2, mulmod(y, z, p), p)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Compute G·u1 + P·u2 using the precomputed points for G and P (see {_preComputeJacobianPoints}).
|
||||
*
|
||||
* Uses Strauss Shamir trick for EC multiplication
|
||||
* https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method
|
||||
*
|
||||
* We optimize this for 2 bits at a time rather than a single bit. The individual points for a single pass are
|
||||
* precomputed. Overall this reduces the number of additions while keeping the same number of
|
||||
* doublings
|
||||
*/
|
||||
function _jMultShamir(
|
||||
JPoint[16] memory points,
|
||||
uint256 u1,
|
||||
uint256 u2
|
||||
) private view returns (uint256 rx, uint256 ry) {
|
||||
uint256 x = 0;
|
||||
uint256 y = 0;
|
||||
uint256 z = 0;
|
||||
unchecked {
|
||||
for (uint256 i = 0; i < 128; ++i) {
|
||||
if (z > 0) {
|
||||
(x, y, z) = _jDouble(x, y, z);
|
||||
(x, y, z) = _jDouble(x, y, z);
|
||||
}
|
||||
// Read 2 bits of u1, and 2 bits of u2. Combining the two gives the lookup index in the table.
|
||||
uint256 pos = ((u1 >> 252) & 0xc) | ((u2 >> 254) & 0x3);
|
||||
// Points that have z = 0 are points at infinity. They are the additive 0 of the group
|
||||
// - if the lookup point is a 0, we can skip it
|
||||
// - otherwise:
|
||||
// - if the current point (x, y, z) is 0, we use the lookup point as our new value (0+P=P)
|
||||
// - if the current point (x, y, z) is not 0, both points are valid and we can use `_jAdd`
|
||||
if (points[pos].z != 0) {
|
||||
if (z == 0) {
|
||||
(x, y, z) = (points[pos].x, points[pos].y, points[pos].z);
|
||||
} else {
|
||||
(x, y, z) = _jAdd(points[pos], x, y, z);
|
||||
}
|
||||
}
|
||||
u1 <<= 2;
|
||||
u2 <<= 2;
|
||||
}
|
||||
}
|
||||
return _affineFromJacobian(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Precompute a matrice of useful jacobian points associated with a given P. This can be seen as a 4x4 matrix
|
||||
* that contains combination of P and G (generator) up to 3 times each. See the table below:
|
||||
*
|
||||
* ┌────┬─────────────────────┐
|
||||
* │ i │ 0 1 2 3 │
|
||||
* ├────┼─────────────────────┤
|
||||
* │ 0 │ 0 p 2p 3p │
|
||||
* │ 4 │ g g+p g+2p g+3p │
|
||||
* │ 8 │ 2g 2g+p 2g+2p 2g+3p │
|
||||
* │ 12 │ 3g 3g+p 3g+2p 3g+3p │
|
||||
* └────┴─────────────────────┘
|
||||
*
|
||||
* Note that `_jAdd` (and thus `_jAddPoint`) does not handle the case where one of the inputs is a point at
|
||||
* infinity (z = 0). However, we know that since `N ≡ 1 mod 2` and `N ≡ 1 mod 3`, there is no point P such that
|
||||
* 2P = 0 or 3P = 0. This guarantees that g, 2g, 3g, p, 2p, 3p are all non-zero, and that all `_jAddPoint` calls
|
||||
* have valid inputs.
|
||||
*/
|
||||
function _preComputeJacobianPoints(uint256 px, uint256 py) private pure returns (JPoint[16] memory points) {
|
||||
points[0x00] = JPoint(0, 0, 0); // 0,0
|
||||
points[0x01] = JPoint(px, py, 1); // 1,0 (p)
|
||||
points[0x04] = JPoint(GX, GY, 1); // 0,1 (g)
|
||||
points[0x02] = _jDoublePoint(points[0x01]); // 2,0 (2p)
|
||||
points[0x08] = _jDoublePoint(points[0x04]); // 0,2 (2g)
|
||||
points[0x03] = _jAddPoint(points[0x01], points[0x02]); // 3,0 (p+2p = 3p)
|
||||
points[0x05] = _jAddPoint(points[0x01], points[0x04]); // 1,1 (p+g)
|
||||
points[0x06] = _jAddPoint(points[0x02], points[0x04]); // 2,1 (2p+g)
|
||||
points[0x07] = _jAddPoint(points[0x03], points[0x04]); // 3,1 (3p+g)
|
||||
points[0x09] = _jAddPoint(points[0x01], points[0x08]); // 1,2 (p+2g)
|
||||
points[0x0a] = _jAddPoint(points[0x02], points[0x08]); // 2,2 (2p+2g)
|
||||
points[0x0b] = _jAddPoint(points[0x03], points[0x08]); // 3,2 (3p+2g)
|
||||
points[0x0c] = _jAddPoint(points[0x04], points[0x08]); // 0,3 (g+2g = 3g)
|
||||
points[0x0d] = _jAddPoint(points[0x01], points[0x0c]); // 1,3 (p+3g)
|
||||
points[0x0e] = _jAddPoint(points[0x02], points[0x0c]); // 2,3 (2p+3g)
|
||||
points[0x0f] = _jAddPoint(points[0x03], points[0x0c]); // 3,3 (3p+3g)
|
||||
}
|
||||
|
||||
function _jAddPoint(JPoint memory p1, JPoint memory p2) private pure returns (JPoint memory) {
|
||||
(uint256 x, uint256 y, uint256 z) = _jAdd(p1, p2.x, p2.y, p2.z);
|
||||
return JPoint(x, y, z);
|
||||
}
|
||||
|
||||
function _jDoublePoint(JPoint memory p) private pure returns (JPoint memory) {
|
||||
(uint256 x, uint256 y, uint256 z) = _jDouble(p.x, p.y, p.z);
|
||||
return JPoint(x, y, z);
|
||||
}
|
||||
}
|
||||
154
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/RSA.sol
generated
vendored
Executable file
154
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/RSA.sol
generated
vendored
Executable file
@@ -0,0 +1,154 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/RSA.sol)
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
|
||||
/**
|
||||
* @dev RSA PKCS#1 v1.5 signature verification implementation according to https://datatracker.ietf.org/doc/html/rfc8017[RFC8017].
|
||||
*
|
||||
* This library supports PKCS#1 v1.5 padding to avoid malleability via chosen plaintext attacks in practical implementations.
|
||||
* The padding follows the EMSA-PKCS1-v1_5-ENCODE encoding definition as per section 9.2 of the RFC. This padding makes
|
||||
* RSA semantically secure for signing messages.
|
||||
*
|
||||
* Inspired by https://github.com/adria0/SolRsaVerify/blob/79c6182cabb9102ea69d4a2e996816091d5f1cd1[Adrià Massanet's work] (GNU General Public License v3.0).
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library RSA {
|
||||
/**
|
||||
* @dev Same as {pkcs1Sha256} but using SHA256 to calculate the digest of `data`.
|
||||
*/
|
||||
function pkcs1Sha256(
|
||||
bytes memory data,
|
||||
bytes memory s,
|
||||
bytes memory e,
|
||||
bytes memory n
|
||||
) internal view returns (bool) {
|
||||
return pkcs1Sha256(sha256(data), s, e, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Verifies a PKCSv1.5 signature given a digest according to the verification
|
||||
* method described in https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2[section 8.2.2 of RFC8017] with
|
||||
* support for explicit or implicit NULL parameters in the DigestInfo (no other optional parameters are supported).
|
||||
*
|
||||
* IMPORTANT: For security reason, this function requires the signature and modulus to have a length of at least
|
||||
* 2048 bits. If you use a smaller key, consider replacing it with a larger, more secure, one.
|
||||
*
|
||||
* WARNING: This verification algorithm doesn't prevent replayability. If called multiple times with the same
|
||||
* digest, public key and (valid signature), it will return true every time. Consider including an onchain nonce
|
||||
* or unique identifier in the message to prevent replay attacks.
|
||||
*
|
||||
* WARNING: This verification algorithm supports any exponent. NIST recommends using `65537` (or higher).
|
||||
* That is the default value many libraries use, such as OpenSSL. Developers may choose to reject public keys
|
||||
* using a low exponent out of security concerns.
|
||||
*
|
||||
* @param digest the digest to verify
|
||||
* @param s is a buffer containing the signature
|
||||
* @param e is the exponent of the public key
|
||||
* @param n is the modulus of the public key
|
||||
*/
|
||||
function pkcs1Sha256(bytes32 digest, bytes memory s, bytes memory e, bytes memory n) internal view returns (bool) {
|
||||
unchecked {
|
||||
// cache and check length
|
||||
uint256 length = n.length;
|
||||
if (
|
||||
length < 0x100 || // Enforce 2048 bits minimum
|
||||
length != s.length // signature must have the same length as the finite field
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that s < n to ensure there's only one valid signature for a given message
|
||||
for (uint256 i = 0; i < length; i += 0x20) {
|
||||
uint256 p = Math.min(i, length - 0x20);
|
||||
bytes32 sp = _unsafeReadBytes32(s, p);
|
||||
bytes32 np = _unsafeReadBytes32(n, p);
|
||||
if (sp < np) {
|
||||
// s < n in the upper bits (everything before is equal) → s < n globally: ok
|
||||
break;
|
||||
} else if (sp > np || p == length - 0x20) {
|
||||
// s > n in the upper bits (everything before is equal) → s > n globally: fail
|
||||
// or
|
||||
// s = n and we are looking at the lower bits → s = n globally: fail
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// RSAVP1 https://datatracker.ietf.org/doc/html/rfc8017#section-5.2.2
|
||||
// The previous check guarantees that n > 0. Therefore modExp cannot revert.
|
||||
bytes memory buffer = Math.modExp(s, e, n);
|
||||
|
||||
// Check that buffer is well encoded:
|
||||
// buffer ::= 0x00 | 0x01 | PS | 0x00 | DigestInfo
|
||||
//
|
||||
// With
|
||||
// - PS is padding filled with 0xFF
|
||||
// - DigestInfo ::= SEQUENCE {
|
||||
// digestAlgorithm AlgorithmIdentifier,
|
||||
// [optional algorithm parameters] -- not currently supported
|
||||
// digest OCTET STRING
|
||||
// }
|
||||
|
||||
// Get AlgorithmIdentifier from the DigestInfo, and set the config accordingly
|
||||
// - params: includes 00 + first part of DigestInfo
|
||||
// - mask: filter to check the params
|
||||
// - offset: length of the suffix (including digest)
|
||||
bytes32 params; // 0x00 | DigestInfo
|
||||
bytes32 mask;
|
||||
uint256 offset;
|
||||
|
||||
// Digest is expected at the end of the buffer. Therefore if NULL param is present,
|
||||
// it should be at 32 (digest) + 2 bytes from the end. To those 34 bytes, we add the
|
||||
// OID (9 bytes) and its length (2 bytes) to get the position of the DigestInfo sequence,
|
||||
// which is expected to have a length of 0x31 when the NULL param is present or 0x2f if not.
|
||||
if (bytes1(_unsafeReadBytes32(buffer, length - 0x32)) == 0x31) {
|
||||
offset = 0x34;
|
||||
// 00 (1 byte) | SEQUENCE length (0x31) = 3031 (2 bytes) | SEQUENCE length (0x0d) = 300d (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes)
|
||||
// SHA256 OID = 608648016503040201 (9 bytes) | NULL = 0500 (2 bytes) (explicit) | OCTET_STRING length (0x20) = 0420 (2 bytes)
|
||||
params = 0x003031300d060960864801650304020105000420000000000000000000000000;
|
||||
mask = 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000; // (20 bytes)
|
||||
} else if (bytes1(_unsafeReadBytes32(buffer, length - 0x30)) == 0x2F) {
|
||||
offset = 0x32;
|
||||
// 00 (1 byte) | SEQUENCE length (0x2f) = 302f (2 bytes) | SEQUENCE length (0x0b) = 300b (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes)
|
||||
// SHA256 OID = 608648016503040201 (9 bytes) | NULL = <implicit> | OCTET_STRING length (0x20) = 0420 (2 bytes)
|
||||
params = 0x00302f300b060960864801650304020104200000000000000000000000000000;
|
||||
mask = 0xffffffffffffffffffffffffffffffffffff0000000000000000000000000000; // (18 bytes)
|
||||
} else {
|
||||
// unknown
|
||||
return false;
|
||||
}
|
||||
|
||||
// Length is at least 0x100 and offset is at most 0x34, so this is safe. There is always some padding.
|
||||
uint256 paddingEnd = length - offset;
|
||||
|
||||
// The padding has variable (arbitrary) length, so we check it byte per byte in a loop.
|
||||
// This is required to ensure non-malleability. Not checking would allow an attacker to
|
||||
// use the padding to manipulate the message in order to create a valid signature out of
|
||||
// multiple valid signatures.
|
||||
for (uint256 i = 2; i < paddingEnd; ++i) {
|
||||
if (bytes1(_unsafeReadBytes32(buffer, i)) != 0xFF) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All the other parameters are small enough to fit in a bytes32, so we can check them directly.
|
||||
return
|
||||
bytes2(0x0001) == bytes2(_unsafeReadBytes32(buffer, 0x00)) && // 00 | 01
|
||||
// PS was checked in the loop
|
||||
params == _unsafeReadBytes32(buffer, paddingEnd) & mask && // DigestInfo
|
||||
// Optional parameters are not checked
|
||||
digest == _unsafeReadBytes32(buffer, length - 0x20); // Digest
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Reads a bytes32 from a bytes array without bounds checking.
|
||||
function _unsafeReadBytes32(bytes memory array, uint256 offset) private pure returns (bytes32 result) {
|
||||
// Memory safeness is guaranteed as long as the provided `array` is a Solidity-allocated bytes array
|
||||
// and `offset` is within bounds. This is the case for all calls to this private function from {pkcs1Sha256}.
|
||||
assembly ("memory-safe") {
|
||||
result := mload(add(add(array, 0x20), offset))
|
||||
}
|
||||
}
|
||||
}
|
||||
135
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol
generated
vendored
Executable file
135
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol
generated
vendored
Executable file
@@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/SignatureChecker.sol)
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {ECDSA} from "./ECDSA.sol";
|
||||
import {IERC1271} from "../../interfaces/IERC1271.sol";
|
||||
import {IERC7913SignatureVerifier} from "../../interfaces/IERC7913.sol";
|
||||
import {Bytes} from "../../utils/Bytes.sol";
|
||||
|
||||
/**
|
||||
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support:
|
||||
*
|
||||
* * ECDSA signatures from externally owned accounts (EOAs)
|
||||
* * ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet (previously Gnosis Safe)
|
||||
* * ERC-7913 signatures from keys that do not have an Ethereum address of their own
|
||||
*
|
||||
* See https://eips.ethereum.org/EIPS/eip-1271[ERC-1271] and https://eips.ethereum.org/EIPS/eip-7913[ERC-7913].
|
||||
*/
|
||||
library SignatureChecker {
|
||||
using Bytes for bytes;
|
||||
|
||||
/**
|
||||
* @dev Checks if a signature is valid for a given signer and data hash. If the signer has code, the
|
||||
* signature is validated against it 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).
|
||||
*
|
||||
* NOTE: For an extended version of this function that supports ERC-7913 signatures, see {isValidSignatureNow-bytes-bytes32-bytes-}.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Verifies a signature for a given ERC-7913 signer and hash.
|
||||
*
|
||||
* The signer is a `bytes` object that is the concatenation of an address and optionally a key:
|
||||
* `verifier || key`. A signer must be at least 20 bytes long.
|
||||
*
|
||||
* Verification is done as follows:
|
||||
*
|
||||
* * If `signer.length < 20`: verification fails
|
||||
* * If `signer.length == 20`: verification is done using {isValidSignatureNow}
|
||||
* * Otherwise: verification is done using {IERC7913SignatureVerifier}
|
||||
*
|
||||
* 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(
|
||||
bytes memory signer,
|
||||
bytes32 hash,
|
||||
bytes memory signature
|
||||
) internal view returns (bool) {
|
||||
if (signer.length < 20) {
|
||||
return false;
|
||||
} else if (signer.length == 20) {
|
||||
return isValidSignatureNow(address(bytes20(signer)), hash, signature);
|
||||
} else {
|
||||
(bool success, bytes memory result) = address(bytes20(signer)).staticcall(
|
||||
abi.encodeCall(IERC7913SignatureVerifier.verify, (signer.slice(20), hash, signature))
|
||||
);
|
||||
return (success &&
|
||||
result.length >= 32 &&
|
||||
abi.decode(result, (bytes32)) == bytes32(IERC7913SignatureVerifier.verify.selector));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Verifies multiple ERC-7913 `signatures` for a given `hash` using a set of `signers`.
|
||||
* Returns `false` if the number of signers and signatures is not the same.
|
||||
*
|
||||
* The signers should be ordered by their `keccak256` hash to ensure efficient duplication check. Unordered
|
||||
* signers are supported, but the uniqueness check will be more expensive.
|
||||
*
|
||||
* 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 areValidSignaturesNow(
|
||||
bytes32 hash,
|
||||
bytes[] memory signers,
|
||||
bytes[] memory signatures
|
||||
) internal view returns (bool) {
|
||||
if (signers.length != signatures.length) return false;
|
||||
|
||||
bytes32 lastId = bytes32(0);
|
||||
|
||||
for (uint256 i = 0; i < signers.length; ++i) {
|
||||
bytes memory signer = signers[i];
|
||||
|
||||
// If one of the signatures is invalid, reject the batch
|
||||
if (!isValidSignatureNow(signer, hash, signatures[i])) return false;
|
||||
|
||||
bytes32 id = keccak256(signer);
|
||||
// If the current signer ID is greater than all previous IDs, then this is a new signer.
|
||||
if (lastId < id) {
|
||||
lastId = id;
|
||||
} else {
|
||||
// If this signer id is not greater than all the previous ones, verify that it is not a duplicate of a previous one
|
||||
// This loop is never executed if the signers are ordered by id.
|
||||
for (uint256 j = 0; j < i; ++j) {
|
||||
if (id == keccak256(signers[j])) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
207
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/draft-ERC7739Utils.sol
generated
vendored
Executable file
207
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/draft-ERC7739Utils.sol
generated
vendored
Executable file
@@ -0,0 +1,207 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/draft-ERC7739Utils.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Calldata} from "../Calldata.sol";
|
||||
|
||||
/**
|
||||
* @dev Utilities to process https://ercs.ethereum.org/ERCS/erc-7739[ERC-7739] typed data signatures
|
||||
* that are specific to an EIP-712 domain.
|
||||
*
|
||||
* This library provides methods to wrap, unwrap and operate over typed data signatures with a defensive
|
||||
* rehashing mechanism that includes the app's xref:api:utils/cryptography#EIP712-_domainSeparatorV4[EIP-712]
|
||||
* and preserves readability of the signed content using an EIP-712 nested approach.
|
||||
*
|
||||
* A smart contract domain can validate a signature for a typed data structure in two ways:
|
||||
*
|
||||
* - As an application validating a typed data signature. See {typedDataSignStructHash}.
|
||||
* - As a smart contract validating a raw message signature. See {personalSignStructHash}.
|
||||
*
|
||||
* NOTE: A provider for a smart contract wallet would need to return this signature as the
|
||||
* result of a call to `personal_sign` or `eth_signTypedData`, and this may be unsupported by
|
||||
* API clients that expect a return value of 129 bytes, or specifically the `r,s,v` parameters
|
||||
* of an xref:api:utils/cryptography#ECDSA[ECDSA] signature, as is for example specified for
|
||||
* xref:api:utils/cryptography#EIP712[EIP-712].
|
||||
*/
|
||||
library ERC7739Utils {
|
||||
/**
|
||||
* @dev An EIP-712 type to represent "personal" signatures
|
||||
* (i.e. mimic of `personal_sign` for smart contracts).
|
||||
*/
|
||||
bytes32 private constant PERSONAL_SIGN_TYPEHASH = keccak256("PersonalSign(bytes prefixed)");
|
||||
|
||||
/**
|
||||
* @dev Nest a signature for a given EIP-712 type into a nested signature for the domain of the app.
|
||||
*
|
||||
* Counterpart of {decodeTypedDataSig} to extract the original signature and the nested components.
|
||||
*/
|
||||
function encodeTypedDataSig(
|
||||
bytes memory signature,
|
||||
bytes32 appSeparator,
|
||||
bytes32 contentsHash,
|
||||
string memory contentsDescr
|
||||
) internal pure returns (bytes memory) {
|
||||
return
|
||||
abi.encodePacked(signature, appSeparator, contentsHash, contentsDescr, uint16(bytes(contentsDescr).length));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parses a nested signature into its components.
|
||||
*
|
||||
* Constructed as follows:
|
||||
*
|
||||
* `signature ‖ APP_DOMAIN_SEPARATOR ‖ contentsHash ‖ contentsDescr ‖ uint16(contentsDescr.length)`
|
||||
*
|
||||
* - `signature` is the signature for the (ERC-7739) nested struct hash. This signature indirectly signs over the
|
||||
* original "contents" hash (from the app) and the account's domain separator.
|
||||
* - `APP_DOMAIN_SEPARATOR` is the EIP-712 {EIP712-_domainSeparatorV4} of the application smart contract that is
|
||||
* requesting the signature verification (though ERC-1271).
|
||||
* - `contentsHash` is the hash of the underlying data structure or message.
|
||||
* - `contentsDescr` is a descriptor of the "contents" part of the the EIP-712 type of the nested signature.
|
||||
*
|
||||
* NOTE: This function returns empty if the input format is invalid instead of reverting.
|
||||
* data instead.
|
||||
*/
|
||||
function decodeTypedDataSig(
|
||||
bytes calldata encodedSignature
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes calldata signature, bytes32 appSeparator, bytes32 contentsHash, string calldata contentsDescr)
|
||||
{
|
||||
unchecked {
|
||||
uint256 sigLength = encodedSignature.length;
|
||||
|
||||
// 66 bytes = contentsDescrLength (2 bytes) + contentsHash (32 bytes) + APP_DOMAIN_SEPARATOR (32 bytes).
|
||||
if (sigLength < 66) return (Calldata.emptyBytes(), 0, 0, Calldata.emptyString());
|
||||
|
||||
uint256 contentsDescrEnd = sigLength - 2; // Last 2 bytes
|
||||
uint256 contentsDescrLength = uint16(bytes2(encodedSignature[contentsDescrEnd:]));
|
||||
|
||||
// Check for space for `contentsDescr` in addition to the 66 bytes documented above
|
||||
if (sigLength < 66 + contentsDescrLength) return (Calldata.emptyBytes(), 0, 0, Calldata.emptyString());
|
||||
|
||||
uint256 contentsHashEnd = contentsDescrEnd - contentsDescrLength;
|
||||
uint256 separatorEnd = contentsHashEnd - 32;
|
||||
uint256 signatureEnd = separatorEnd - 32;
|
||||
|
||||
signature = encodedSignature[:signatureEnd];
|
||||
appSeparator = bytes32(encodedSignature[signatureEnd:separatorEnd]);
|
||||
contentsHash = bytes32(encodedSignature[separatorEnd:contentsHashEnd]);
|
||||
contentsDescr = string(encodedSignature[contentsHashEnd:contentsDescrEnd]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Nests an `ERC-191` digest into a `PersonalSign` EIP-712 struct, and returns the corresponding struct hash.
|
||||
* This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} before
|
||||
* being verified/recovered.
|
||||
*
|
||||
* This is used to simulates the `personal_sign` RPC method in the context of smart contracts.
|
||||
*/
|
||||
function personalSignStructHash(bytes32 contents) internal pure returns (bytes32) {
|
||||
return keccak256(abi.encode(PERSONAL_SIGN_TYPEHASH, contents));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Nests an `EIP-712` hash (`contents`) into a `TypedDataSign` EIP-712 struct, and returns the corresponding
|
||||
* struct hash. This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash}
|
||||
* before being verified/recovered.
|
||||
*/
|
||||
function typedDataSignStructHash(
|
||||
string calldata contentsName,
|
||||
string calldata contentsType,
|
||||
bytes32 contentsHash,
|
||||
bytes memory domainBytes
|
||||
) internal pure returns (bytes32 result) {
|
||||
return
|
||||
bytes(contentsName).length == 0
|
||||
? bytes32(0)
|
||||
: keccak256(
|
||||
abi.encodePacked(typedDataSignTypehash(contentsName, contentsType), contentsHash, domainBytes)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {typedDataSignStructHash-string-string-bytes32-bytes} that takes a content descriptor
|
||||
* and decodes the `contentsName` and `contentsType` out of it.
|
||||
*/
|
||||
function typedDataSignStructHash(
|
||||
string calldata contentsDescr,
|
||||
bytes32 contentsHash,
|
||||
bytes memory domainBytes
|
||||
) internal pure returns (bytes32 result) {
|
||||
(string calldata contentsName, string calldata contentsType) = decodeContentsDescr(contentsDescr);
|
||||
|
||||
return typedDataSignStructHash(contentsName, contentsType, contentsHash, domainBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Compute the EIP-712 typehash of the `TypedDataSign` structure for a given type (and typename).
|
||||
*/
|
||||
function typedDataSignTypehash(
|
||||
string calldata contentsName,
|
||||
string calldata contentsType
|
||||
) internal pure returns (bytes32) {
|
||||
return
|
||||
keccak256(
|
||||
abi.encodePacked(
|
||||
"TypedDataSign(",
|
||||
contentsName,
|
||||
" contents,string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)",
|
||||
contentsType
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Parse the type name out of the ERC-7739 contents type description. Supports both the implicit and explicit
|
||||
* modes.
|
||||
*
|
||||
* Following ERC-7739 specifications, a `contentsName` is considered invalid if it's empty or it contains
|
||||
* any of the following bytes , )\x00
|
||||
*
|
||||
* If the `contentsType` is invalid, this returns an empty string. Otherwise, the return string has non-zero
|
||||
* length.
|
||||
*/
|
||||
function decodeContentsDescr(
|
||||
string calldata contentsDescr
|
||||
) internal pure returns (string calldata contentsName, string calldata contentsType) {
|
||||
bytes calldata buffer = bytes(contentsDescr);
|
||||
if (buffer.length == 0) {
|
||||
// pass through (fail)
|
||||
} else if (buffer[buffer.length - 1] == bytes1(")")) {
|
||||
// Implicit mode: read contentsName from the beginning, and keep the complete descr
|
||||
for (uint256 i = 0; i < buffer.length; ++i) {
|
||||
bytes1 current = buffer[i];
|
||||
if (current == bytes1("(")) {
|
||||
// if name is empty - passthrough (fail)
|
||||
if (i == 0) break;
|
||||
// we found the end of the contentsName
|
||||
return (string(buffer[:i]), contentsDescr);
|
||||
} else if (_isForbiddenChar(current)) {
|
||||
// we found an invalid character (forbidden) - passthrough (fail)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Explicit mode: read contentsName from the end, and remove it from the descr
|
||||
for (uint256 i = buffer.length; i > 0; --i) {
|
||||
bytes1 current = buffer[i - 1];
|
||||
if (current == bytes1(")")) {
|
||||
// we found the end of the contentsName
|
||||
return (string(buffer[i:]), string(buffer[:i]));
|
||||
} else if (_isForbiddenChar(current)) {
|
||||
// we found an invalid character (forbidden) - passthrough (fail)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (Calldata.emptyString(), Calldata.emptyString());
|
||||
}
|
||||
|
||||
function _isForbiddenChar(bytes1 char) private pure returns (bool) {
|
||||
return char == 0x00 || char == bytes1(" ") || char == bytes1(",") || char == bytes1("(") || char == bytes1(")");
|
||||
}
|
||||
}
|
||||
23
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol
generated
vendored
Executable file
23
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol
generated
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/AbstractSigner.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/**
|
||||
* @dev Abstract contract for signature validation.
|
||||
*
|
||||
* Developers must implement {_rawSignatureValidation} and use it as the lowest-level signature validation mechanism.
|
||||
*
|
||||
* @custom:stateless
|
||||
*/
|
||||
abstract contract AbstractSigner {
|
||||
/**
|
||||
* @dev Signature validation algorithm.
|
||||
*
|
||||
* WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves
|
||||
* cryptographic verification. It is important to review and test thoroughly before deployment. Consider
|
||||
* using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA],
|
||||
* xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]).
|
||||
*/
|
||||
function _rawSignatureValidation(bytes32 hash, bytes calldata signature) internal view virtual returns (bool);
|
||||
}
|
||||
252
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913.sol
generated
vendored
Executable file
252
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913.sol
generated
vendored
Executable file
@@ -0,0 +1,252 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/MultiSignerERC7913.sol)
|
||||
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {SignatureChecker} from "../SignatureChecker.sol";
|
||||
import {EnumerableSet} from "../../structs/EnumerableSet.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of {AbstractSigner} using multiple ERC-7913 signers with a threshold-based
|
||||
* signature verification system.
|
||||
*
|
||||
* This contract allows managing a set of authorized signers and requires a minimum number of
|
||||
* signatures (threshold) to approve operations. It uses ERC-7913 formatted signers, which
|
||||
* makes it natively compatible with ECDSA and ERC-1271 signers.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract MyMultiSignerAccount is Account, MultiSignerERC7913, Initializable {
|
||||
* function initialize(bytes[] memory signers, uint64 threshold) public initializer {
|
||||
* _addSigners(signers);
|
||||
* _setThreshold(threshold);
|
||||
* }
|
||||
*
|
||||
* function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
|
||||
* _addSigners(signers);
|
||||
* }
|
||||
*
|
||||
* function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
|
||||
* _removeSigners(signers);
|
||||
* }
|
||||
*
|
||||
* function setThreshold(uint64 threshold) public onlyEntryPointOrSelf {
|
||||
* _setThreshold(threshold);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* IMPORTANT: Failing to properly initialize the signers and threshold either during construction
|
||||
* (if used standalone) or during initialization (if used as a clone) may leave the contract
|
||||
* either front-runnable or unusable.
|
||||
*/
|
||||
abstract contract MultiSignerERC7913 is AbstractSigner {
|
||||
using EnumerableSet for EnumerableSet.BytesSet;
|
||||
using SignatureChecker for *;
|
||||
|
||||
EnumerableSet.BytesSet private _signers;
|
||||
uint64 private _threshold;
|
||||
|
||||
/// @dev Emitted when a signer is added.
|
||||
event ERC7913SignerAdded(bytes indexed signers);
|
||||
|
||||
/// @dev Emitted when a signers is removed.
|
||||
event ERC7913SignerRemoved(bytes indexed signers);
|
||||
|
||||
/// @dev Emitted when the threshold is updated.
|
||||
event ERC7913ThresholdSet(uint64 threshold);
|
||||
|
||||
/// @dev The `signer` already exists.
|
||||
error MultiSignerERC7913AlreadyExists(bytes signer);
|
||||
|
||||
/// @dev The `signer` does not exist.
|
||||
error MultiSignerERC7913NonexistentSigner(bytes signer);
|
||||
|
||||
/// @dev The `signer` is less than 20 bytes long.
|
||||
error MultiSignerERC7913InvalidSigner(bytes signer);
|
||||
|
||||
/// @dev The `threshold` is zero.
|
||||
error MultiSignerERC7913ZeroThreshold();
|
||||
|
||||
/// @dev The `threshold` is unreachable given the number of `signers`.
|
||||
error MultiSignerERC7913UnreachableThreshold(uint64 signers, uint64 threshold);
|
||||
|
||||
constructor(bytes[] memory signers_, uint64 threshold_) {
|
||||
_addSigners(signers_);
|
||||
_setThreshold(threshold_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns a slice of the set of authorized signers.
|
||||
*
|
||||
* Using `start = 0` and `end = type(uint64).max` will return the entire set of signers.
|
||||
*
|
||||
* WARNING: Depending on the `start` and `end`, this operation can copy a large amount of data to memory, which
|
||||
* can be expensive. This is designed for view accessors queried without gas fees. Using it in state-changing
|
||||
* functions may become uncallable if the slice grows too large.
|
||||
*/
|
||||
function getSigners(uint64 start, uint64 end) public view virtual returns (bytes[] memory) {
|
||||
return _signers.values(start, end);
|
||||
}
|
||||
|
||||
/// @dev Returns the number of authorized signers
|
||||
function getSignerCount() public view virtual returns (uint256) {
|
||||
return _signers.length();
|
||||
}
|
||||
|
||||
/// @dev Returns whether the `signer` is an authorized signer.
|
||||
function isSigner(bytes memory signer) public view virtual returns (bool) {
|
||||
return _signers.contains(signer);
|
||||
}
|
||||
|
||||
/// @dev Returns the minimum number of signers required to approve a multisignature operation.
|
||||
function threshold() public view virtual returns (uint64) {
|
||||
return _threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds the `newSigners` to those allowed to sign on behalf of this contract.
|
||||
* Internal version without access control.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * Each of `newSigners` must be at least 20 bytes long. Reverts with {MultiSignerERC7913InvalidSigner} if not.
|
||||
* * Each of `newSigners` must not be authorized. See {isSigner}. Reverts with {MultiSignerERC7913AlreadyExists} if so.
|
||||
*/
|
||||
function _addSigners(bytes[] memory newSigners) internal virtual {
|
||||
for (uint256 i = 0; i < newSigners.length; ++i) {
|
||||
bytes memory signer = newSigners[i];
|
||||
require(signer.length >= 20, MultiSignerERC7913InvalidSigner(signer));
|
||||
require(_signers.add(signer), MultiSignerERC7913AlreadyExists(signer));
|
||||
emit ERC7913SignerAdded(signer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes the `oldSigners` from the authorized signers. Internal version without access control.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * Each of `oldSigners` must be authorized. See {isSigner}. Otherwise {MultiSignerERC7913NonexistentSigner} is thrown.
|
||||
* * See {_validateReachableThreshold} for the threshold validation.
|
||||
*/
|
||||
function _removeSigners(bytes[] memory oldSigners) internal virtual {
|
||||
for (uint256 i = 0; i < oldSigners.length; ++i) {
|
||||
bytes memory signer = oldSigners[i];
|
||||
require(_signers.remove(signer), MultiSignerERC7913NonexistentSigner(signer));
|
||||
emit ERC7913SignerRemoved(signer);
|
||||
}
|
||||
_validateReachableThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the signatures `threshold` required to approve a multisignature operation.
|
||||
* Internal version without access control.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * See {_validateReachableThreshold} for the threshold validation.
|
||||
*/
|
||||
function _setThreshold(uint64 newThreshold) internal virtual {
|
||||
require(newThreshold > 0, MultiSignerERC7913ZeroThreshold());
|
||||
_threshold = newThreshold;
|
||||
_validateReachableThreshold();
|
||||
emit ERC7913ThresholdSet(newThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validates the current threshold is reachable.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * The {getSignerCount} must be greater or equal than to the {threshold}. Throws
|
||||
* {MultiSignerERC7913UnreachableThreshold} if not.
|
||||
*/
|
||||
function _validateReachableThreshold() internal view virtual {
|
||||
uint256 signersLength = _signers.length();
|
||||
uint64 currentThreshold = threshold();
|
||||
require(
|
||||
signersLength >= currentThreshold,
|
||||
MultiSignerERC7913UnreachableThreshold(
|
||||
uint64(signersLength), // Safe cast. Economically impossible to overflow.
|
||||
currentThreshold
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decodes, validates the signature and checks the signers are authorized.
|
||||
* See {_validateSignatures} and {_validateThreshold} for more details.
|
||||
*
|
||||
* Example of signature encoding:
|
||||
*
|
||||
* ```solidity
|
||||
* // Encode signers (verifier || key)
|
||||
* bytes memory signer1 = abi.encodePacked(verifier1, key1);
|
||||
* bytes memory signer2 = abi.encodePacked(verifier2, key2);
|
||||
*
|
||||
* // Order signers by their id
|
||||
* if (keccak256(signer1) > keccak256(signer2)) {
|
||||
* (signer1, signer2) = (signer2, signer1);
|
||||
* (signature1, signature2) = (signature2, signature1);
|
||||
* }
|
||||
*
|
||||
* // Assign ordered signers and signatures
|
||||
* bytes[] memory signers = new bytes[](2);
|
||||
* bytes[] memory signatures = new bytes[](2);
|
||||
* signers[0] = signer1;
|
||||
* signatures[0] = signature1;
|
||||
* signers[1] = signer2;
|
||||
* signatures[1] = signature2;
|
||||
*
|
||||
* // Encode the multi signature
|
||||
* bytes memory signature = abi.encode(signers, signatures);
|
||||
* ```
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * The `signature` must be encoded as `abi.encode(signers, signatures)`.
|
||||
*/
|
||||
function _rawSignatureValidation(
|
||||
bytes32 hash,
|
||||
bytes calldata signature
|
||||
) internal view virtual override returns (bool) {
|
||||
if (signature.length == 0) return false; // For ERC-7739 compatibility
|
||||
(bytes[] memory signers, bytes[] memory signatures) = abi.decode(signature, (bytes[], bytes[]));
|
||||
return _validateThreshold(signers) && _validateSignatures(hash, signers, signatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validates the signatures using the signers and their corresponding signatures.
|
||||
* Returns whether the signers are authorized and the signatures are valid for the given hash.
|
||||
*
|
||||
* IMPORTANT: Sorting the signers by their `keccak256` hash will improve the gas efficiency of this function.
|
||||
* See {SignatureChecker-areValidSignaturesNow-bytes32-bytes[]-bytes[]} for more details.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * The `signatures` and `signers` arrays must be equal in length. Returns false otherwise.
|
||||
*/
|
||||
function _validateSignatures(
|
||||
bytes32 hash,
|
||||
bytes[] memory signers,
|
||||
bytes[] memory signatures
|
||||
) internal view virtual returns (bool valid) {
|
||||
for (uint256 i = 0; i < signers.length; ++i) {
|
||||
if (!isSigner(signers[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return hash.areValidSignaturesNow(signers, signatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validates that the number of signers meets the {threshold} requirement.
|
||||
* Assumes the signers were already validated. See {_validateSignatures} for more details.
|
||||
*/
|
||||
function _validateThreshold(bytes[] memory validatingSigners) internal view virtual returns (bool) {
|
||||
return validatingSigners.length >= threshold();
|
||||
}
|
||||
}
|
||||
208
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol
generated
vendored
Executable file
208
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol
generated
vendored
Executable file
@@ -0,0 +1,208 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/MultiSignerERC7913Weighted.sol)
|
||||
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import {SafeCast} from "../../math/SafeCast.sol";
|
||||
import {MultiSignerERC7913} from "./MultiSignerERC7913.sol";
|
||||
|
||||
/**
|
||||
* @dev Extension of {MultiSignerERC7913} that supports weighted signatures.
|
||||
*
|
||||
* This contract allows assigning different weights to each signer, enabling more
|
||||
* flexible governance schemes. For example, some signers could have higher weight
|
||||
* than others, allowing for weighted voting or prioritized authorization.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract MyWeightedMultiSignerAccount is Account, MultiSignerERC7913Weighted, Initializable {
|
||||
* function initialize(bytes[] memory signers, uint64[] memory weights, uint64 threshold) public initializer {
|
||||
* _addSigners(signers);
|
||||
* _setSignerWeights(signers, weights);
|
||||
* _setThreshold(threshold);
|
||||
* }
|
||||
*
|
||||
* function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
|
||||
* _addSigners(signers);
|
||||
* }
|
||||
*
|
||||
* function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
|
||||
* _removeSigners(signers);
|
||||
* }
|
||||
*
|
||||
* function setThreshold(uint64 threshold) public onlyEntryPointOrSelf {
|
||||
* _setThreshold(threshold);
|
||||
* }
|
||||
*
|
||||
* function setSignerWeights(bytes[] memory signers, uint64[] memory weights) public onlyEntryPointOrSelf {
|
||||
* _setSignerWeights(signers, weights);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* IMPORTANT: When setting a threshold value, ensure it matches the scale used for signer weights.
|
||||
* For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require at
|
||||
* least two signers (e.g., one with weight 1 and one with weight 3). See {signerWeight}.
|
||||
*/
|
||||
abstract contract MultiSignerERC7913Weighted is MultiSignerERC7913 {
|
||||
using SafeCast for *;
|
||||
|
||||
// Sum of all the extra weights of all signers. Storage packed with `MultiSignerERC7913._threshold`
|
||||
uint64 private _totalExtraWeight;
|
||||
|
||||
// Mapping from signer to extraWeight (in addition to all authorized signers having weight 1)
|
||||
mapping(bytes signer => uint64) private _extraWeights;
|
||||
|
||||
/**
|
||||
* @dev Emitted when a signer's weight is changed.
|
||||
*
|
||||
* NOTE: Not emitted in {_addSigners} or {_removeSigners}. Indexers must rely on {ERC7913SignerAdded}
|
||||
* and {ERC7913SignerRemoved} to index a default weight of 1. See {signerWeight}.
|
||||
*/
|
||||
event ERC7913SignerWeightChanged(bytes indexed signer, uint64 weight);
|
||||
|
||||
/// @dev Thrown when a signer's weight is invalid.
|
||||
error MultiSignerERC7913WeightedInvalidWeight(bytes signer, uint64 weight);
|
||||
|
||||
/// @dev Thrown when the arrays lengths don't match. See {_setSignerWeights}.
|
||||
error MultiSignerERC7913WeightedMismatchedLength();
|
||||
|
||||
constructor(bytes[] memory signers_, uint64[] memory weights_, uint64 threshold_) MultiSignerERC7913(signers_, 1) {
|
||||
_setSignerWeights(signers_, weights_);
|
||||
_setThreshold(threshold_);
|
||||
}
|
||||
|
||||
/// @dev Gets the weight of a signer. Returns 0 if the signer is not authorized.
|
||||
function signerWeight(bytes memory signer) public view virtual returns (uint64) {
|
||||
unchecked {
|
||||
// Safe cast, _setSignerWeights guarantees 1+_extraWeights is a uint64
|
||||
return uint64(isSigner(signer).toUint() * (1 + _extraWeights[signer]));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Gets the total weight of all signers.
|
||||
function totalWeight() public view virtual returns (uint64) {
|
||||
return (getSignerCount() + _totalExtraWeight).toUint64();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets weights for multiple signers at once. Internal version without access control.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * `signers` and `weights` arrays must have the same length. Reverts with {MultiSignerERC7913WeightedMismatchedLength} on mismatch.
|
||||
* * Each signer must exist in the set of authorized signers. Otherwise reverts with {MultiSignerERC7913NonexistentSigner}
|
||||
* * Each weight must be greater than 0. Otherwise reverts with {MultiSignerERC7913WeightedInvalidWeight}
|
||||
* * See {_validateReachableThreshold} for the threshold validation.
|
||||
*
|
||||
* Emits {ERC7913SignerWeightChanged} for each signer.
|
||||
*/
|
||||
function _setSignerWeights(bytes[] memory signers, uint64[] memory weights) internal virtual {
|
||||
require(signers.length == weights.length, MultiSignerERC7913WeightedMismatchedLength());
|
||||
|
||||
uint256 extraWeightAdded = 0;
|
||||
uint256 extraWeightRemoved = 0;
|
||||
for (uint256 i = 0; i < signers.length; ++i) {
|
||||
bytes memory signer = signers[i];
|
||||
require(isSigner(signer), MultiSignerERC7913NonexistentSigner(signer));
|
||||
|
||||
uint64 weight = weights[i];
|
||||
require(weight > 0, MultiSignerERC7913WeightedInvalidWeight(signer, weight));
|
||||
|
||||
unchecked {
|
||||
uint64 oldExtraWeight = _extraWeights[signer];
|
||||
uint64 newExtraWeight = weight - 1;
|
||||
|
||||
if (oldExtraWeight != newExtraWeight) {
|
||||
// Overflow impossible: weight values are bounded by uint64 and economic constraints
|
||||
extraWeightRemoved += oldExtraWeight;
|
||||
extraWeightAdded += _extraWeights[signer] = newExtraWeight;
|
||||
emit ERC7913SignerWeightChanged(signer, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
unchecked {
|
||||
// Safe from underflow: `extraWeightRemoved` is bounded by `_totalExtraWeight` by construction
|
||||
// and weight values are bounded by uint64 and economic constraints
|
||||
_totalExtraWeight = (uint256(_totalExtraWeight) + extraWeightAdded - extraWeightRemoved).toUint64();
|
||||
}
|
||||
_validateReachableThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {MultiSignerERC7913-_addSigners}.
|
||||
*
|
||||
* In cases where {totalWeight} is almost `type(uint64).max` (due to a large `_totalExtraWeight`), adding new
|
||||
* signers could cause the {totalWeight} computation to overflow. Adding a {totalWeight} calls after the new
|
||||
* signers are added ensures no such overflow happens.
|
||||
*/
|
||||
function _addSigners(bytes[] memory newSigners) internal virtual override {
|
||||
super._addSigners(newSigners);
|
||||
|
||||
// This will revert if the new signers cause an overflow
|
||||
_validateReachableThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {MultiSignerERC7913-_removeSigners}.
|
||||
*
|
||||
* Just like {_addSigners}, this function does not emit {ERC7913SignerWeightChanged} events. The
|
||||
* {ERC7913SignerRemoved} event emitted by {MultiSignerERC7913-_removeSigners} is enough to track weights here.
|
||||
*/
|
||||
function _removeSigners(bytes[] memory signers) internal virtual override {
|
||||
// Clean up weights for removed signers
|
||||
//
|
||||
// The `extraWeightRemoved` is bounded by `_totalExtraWeight`. The `super._removeSigners` function will revert
|
||||
// if the signers array contains any duplicates, ensuring each signer's weight is only counted once. Since
|
||||
// `_totalExtraWeight` is stored as a `uint64`, the final subtraction operation is also safe.
|
||||
unchecked {
|
||||
uint64 extraWeightRemoved = 0;
|
||||
for (uint256 i = 0; i < signers.length; ++i) {
|
||||
bytes memory signer = signers[i];
|
||||
|
||||
extraWeightRemoved += _extraWeights[signer];
|
||||
delete _extraWeights[signer];
|
||||
}
|
||||
_totalExtraWeight -= extraWeightRemoved;
|
||||
}
|
||||
super._removeSigners(signers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the threshold for the multisignature operation. Internal version without access control.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* * The {totalWeight} must be `>=` the {threshold}. Otherwise reverts with {MultiSignerERC7913UnreachableThreshold}
|
||||
*
|
||||
* NOTE: This function intentionally does not call `super._validateReachableThreshold` because the base implementation
|
||||
* assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple
|
||||
* implementations of this function may exist in the contract, so important side effects may be missed
|
||||
* depending on the linearization order.
|
||||
*/
|
||||
function _validateReachableThreshold() internal view virtual override {
|
||||
uint64 weight = totalWeight();
|
||||
uint64 currentThreshold = threshold();
|
||||
require(weight >= currentThreshold, MultiSignerERC7913UnreachableThreshold(weight, currentThreshold));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Validates that the total weight of signers meets the threshold requirement.
|
||||
*
|
||||
* NOTE: This function intentionally does not call `super._validateThreshold` because the base implementation
|
||||
* assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple
|
||||
* implementations of this function may exist in the contract, so important side effects may be missed
|
||||
* depending on the linearization order.
|
||||
*/
|
||||
function _validateThreshold(bytes[] memory signers) internal view virtual override returns (bool) {
|
||||
unchecked {
|
||||
uint64 weight = 0;
|
||||
for (uint256 i = 0; i < signers.length; ++i) {
|
||||
// Overflow impossible: weight values are bounded by uint64 and economic constraints
|
||||
weight += signerWeight(signers[i]);
|
||||
}
|
||||
return weight >= threshold();
|
||||
}
|
||||
}
|
||||
}
|
||||
56
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerECDSA.sol
generated
vendored
Executable file
56
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerECDSA.sol
generated
vendored
Executable file
@@ -0,0 +1,56 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerECDSA.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {ECDSA} from "../ECDSA.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#ECDSA[ECDSA] signatures.
|
||||
*
|
||||
* For {Account} usage, a {_setSigner} function is provided to set the {signer} address.
|
||||
* Doing so is easier for a factory, who is likely to use initializable clones of this contract.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract MyAccountECDSA is Account, SignerECDSA, Initializable {
|
||||
* function initialize(address signerAddr) public initializer {
|
||||
* _setSigner(signerAddr);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone)
|
||||
* or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
|
||||
*/
|
||||
abstract contract SignerECDSA is AbstractSigner {
|
||||
address private _signer;
|
||||
|
||||
constructor(address signerAddr) {
|
||||
_setSigner(signerAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the signer with the address of the native signer. This function should be called during construction
|
||||
* or through an initializer.
|
||||
*/
|
||||
function _setSigner(address signerAddr) internal {
|
||||
_signer = signerAddr;
|
||||
}
|
||||
|
||||
/// @dev Return the signer's address.
|
||||
function signer() public view virtual returns (address) {
|
||||
return _signer;
|
||||
}
|
||||
|
||||
/// @inheritdoc AbstractSigner
|
||||
function _rawSignatureValidation(
|
||||
bytes32 hash,
|
||||
bytes calldata signature
|
||||
) internal view virtual override returns (bool) {
|
||||
(address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature);
|
||||
return signer() == recovered && err == ECDSA.RecoverError.NoError;
|
||||
}
|
||||
}
|
||||
25
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerERC7702.sol
generated
vendored
Executable file
25
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerERC7702.sol
generated
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerERC7702.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {ECDSA} from "../ECDSA.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of {AbstractSigner} for implementation for an EOA. Useful for ERC-7702 accounts.
|
||||
*
|
||||
* @custom:stateless
|
||||
*/
|
||||
abstract contract SignerERC7702 is AbstractSigner {
|
||||
/**
|
||||
* @dev Validates the signature using the EOA's address (i.e. `address(this)`).
|
||||
*/
|
||||
function _rawSignatureValidation(
|
||||
bytes32 hash,
|
||||
bytes calldata signature
|
||||
) internal view virtual override returns (bool) {
|
||||
(address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature);
|
||||
return address(this) == recovered && err == ECDSA.RecoverError.NoError;
|
||||
}
|
||||
}
|
||||
63
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerERC7913.sol
generated
vendored
Executable file
63
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerERC7913.sol
generated
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerERC7913.sol)
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {SignatureChecker} from "../SignatureChecker.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of {AbstractSigner} using
|
||||
* https://eips.ethereum.org/EIPS/eip-7913[ERC-7913] signature verification.
|
||||
*
|
||||
* For {Account} usage, a {_setSigner} function is provided to set the ERC-7913 formatted {signer}.
|
||||
* Doing so is easier for a factory, who is likely to use initializable clones of this contract.
|
||||
*
|
||||
* The signer is a `bytes` object that concatenates a verifier address and a key: `verifier || key`.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract MyAccountERC7913 is Account, SignerERC7913, Initializable {
|
||||
* function initialize(bytes memory signer_) public initializer {
|
||||
* _setSigner(signer_);
|
||||
* }
|
||||
*
|
||||
* function setSigner(bytes memory signer_) public onlyEntryPointOrSelf {
|
||||
* _setSigner(signer_);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone)
|
||||
* or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
|
||||
*/
|
||||
|
||||
abstract contract SignerERC7913 is AbstractSigner {
|
||||
bytes private _signer;
|
||||
|
||||
constructor(bytes memory signer_) {
|
||||
_setSigner(signer_);
|
||||
}
|
||||
|
||||
/// @dev Return the ERC-7913 signer (i.e. `verifier || key`).
|
||||
function signer() public view virtual returns (bytes memory) {
|
||||
return _signer;
|
||||
}
|
||||
|
||||
/// @dev Sets the signer (i.e. `verifier || key`) with an ERC-7913 formatted signer.
|
||||
function _setSigner(bytes memory signer_) internal {
|
||||
_signer = signer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Verifies a signature using {SignatureChecker-isValidSignatureNow-bytes-bytes32-bytes-}
|
||||
* with {signer}, `hash` and `signature`.
|
||||
*/
|
||||
function _rawSignatureValidation(
|
||||
bytes32 hash,
|
||||
bytes calldata signature
|
||||
) internal view virtual override returns (bool) {
|
||||
return SignatureChecker.isValidSignatureNow(signer(), hash, signature);
|
||||
}
|
||||
}
|
||||
64
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerP256.sol
generated
vendored
Executable file
64
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerP256.sol
generated
vendored
Executable file
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerP256.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {P256} from "../P256.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#P256[P256] signatures.
|
||||
*
|
||||
* For {Account} usage, a {_setSigner} function is provided to set the {signer} public key.
|
||||
* Doing so is easier for a factory, who is likely to use initializable clones of this contract.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract MyAccountP256 is Account, SignerP256, Initializable {
|
||||
* function initialize(bytes32 qx, bytes32 qy) public initializer {
|
||||
* _setSigner(qx, qy);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone)
|
||||
* or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
|
||||
*/
|
||||
abstract contract SignerP256 is AbstractSigner {
|
||||
bytes32 private _qx;
|
||||
bytes32 private _qy;
|
||||
|
||||
error SignerP256InvalidPublicKey(bytes32 qx, bytes32 qy);
|
||||
|
||||
constructor(bytes32 qx, bytes32 qy) {
|
||||
_setSigner(qx, qy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the signer with a P256 public key. This function should be called during construction
|
||||
* or through an initializer.
|
||||
*/
|
||||
function _setSigner(bytes32 qx, bytes32 qy) internal {
|
||||
if (!P256.isValidPublicKey(qx, qy)) revert SignerP256InvalidPublicKey(qx, qy);
|
||||
_qx = qx;
|
||||
_qy = qy;
|
||||
}
|
||||
|
||||
/// @dev Return the signer's P256 public key.
|
||||
function signer() public view virtual returns (bytes32 qx, bytes32 qy) {
|
||||
return (_qx, _qy);
|
||||
}
|
||||
|
||||
/// @inheritdoc AbstractSigner
|
||||
function _rawSignatureValidation(
|
||||
bytes32 hash,
|
||||
bytes calldata signature
|
||||
) internal view virtual override returns (bool) {
|
||||
if (signature.length < 0x40) return false;
|
||||
bytes32 r = bytes32(signature[0x00:0x20]);
|
||||
bytes32 s = bytes32(signature[0x20:0x40]);
|
||||
(bytes32 qx, bytes32 qy) = signer();
|
||||
return P256.verify(hash, r, s, qx, qy);
|
||||
}
|
||||
}
|
||||
65
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerRSA.sol
generated
vendored
Executable file
65
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/SignerRSA.sol
generated
vendored
Executable file
@@ -0,0 +1,65 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/SignerRSA.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {RSA} from "../RSA.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#RSA[RSA] signatures.
|
||||
*
|
||||
* For {Account} usage, a {_setSigner} function is provided to set the {signer} public key.
|
||||
* Doing so is easier for a factory, who is likely to use initializable clones of this contract.
|
||||
*
|
||||
* Example of usage:
|
||||
*
|
||||
* ```solidity
|
||||
* contract MyAccountRSA is Account, SignerRSA, Initializable {
|
||||
* function initialize(bytes memory e, bytes memory n) public initializer {
|
||||
* _setSigner(e, n);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone)
|
||||
* or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
|
||||
*/
|
||||
abstract contract SignerRSA is AbstractSigner {
|
||||
bytes private _e;
|
||||
bytes private _n;
|
||||
|
||||
constructor(bytes memory e, bytes memory n) {
|
||||
_setSigner(e, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the signer with a RSA public key. This function should be called during construction
|
||||
* or through an initializer.
|
||||
*/
|
||||
function _setSigner(bytes memory e, bytes memory n) internal {
|
||||
_e = e;
|
||||
_n = n;
|
||||
}
|
||||
|
||||
/// @dev Return the signer's RSA public key.
|
||||
function signer() public view virtual returns (bytes memory e, bytes memory n) {
|
||||
return (_e, _n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {AbstractSigner-_rawSignatureValidation}. Verifies a PKCSv1.5 signature by calling
|
||||
* xref:api:utils/cryptography.adoc#RSA-pkcs1Sha256-bytes-bytes-bytes-bytes-[RSA.pkcs1Sha256].
|
||||
*
|
||||
* IMPORTANT: Following the RSASSA-PKCS1-V1_5-VERIFY procedure outlined in RFC8017 (section 8.2.2), the
|
||||
* provided `hash` is used as the `M` (message) and rehashed using SHA256 according to EMSA-PKCS1-v1_5
|
||||
* encoding as per section 9.2 (step 1) of the RFC.
|
||||
*/
|
||||
function _rawSignatureValidation(
|
||||
bytes32 hash,
|
||||
bytes calldata signature
|
||||
) internal view virtual override returns (bool) {
|
||||
(bytes memory e, bytes memory n) = signer();
|
||||
return RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n);
|
||||
}
|
||||
}
|
||||
99
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol
generated
vendored
Executable file
99
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol
generated
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/draft-ERC7739.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {AbstractSigner} from "./AbstractSigner.sol";
|
||||
import {EIP712} from "../EIP712.sol";
|
||||
import {ERC7739Utils} from "../draft-ERC7739Utils.sol";
|
||||
import {IERC1271} from "../../../interfaces/IERC1271.sol";
|
||||
import {MessageHashUtils} from "../MessageHashUtils.sol";
|
||||
import {ShortStrings} from "../../ShortStrings.sol";
|
||||
|
||||
/**
|
||||
* @dev Validates signatures wrapping the message hash in a nested EIP712 type. See {ERC7739Utils}.
|
||||
*
|
||||
* Linking the signature to the EIP-712 domain separator is a security measure to prevent signature replay across different
|
||||
* EIP-712 domains (e.g. a single offchain owner of multiple contracts).
|
||||
*
|
||||
* This contract requires implementing the {_rawSignatureValidation} function, which passes the wrapped message hash,
|
||||
* which may be either an typed data or a personal sign nested type.
|
||||
*
|
||||
* NOTE: xref:api:utils/cryptography#EIP712[EIP-712] uses xref:api:utils/cryptography#ShortStrings[ShortStrings] to
|
||||
* optimize gas costs for short strings (up to 31 characters). Consider that strings longer than that will use storage,
|
||||
* which may limit the ability of the signer to be used within the ERC-4337 validation phase (due to
|
||||
* https://eips.ethereum.org/EIPS/eip-7562#storage-rules[ERC-7562 storage access rules]).
|
||||
*/
|
||||
abstract contract ERC7739 is AbstractSigner, EIP712, IERC1271 {
|
||||
using ERC7739Utils for *;
|
||||
using MessageHashUtils for bytes32;
|
||||
|
||||
/**
|
||||
* @dev Attempts validating the signature in a nested EIP-712 type.
|
||||
*
|
||||
* A nested EIP-712 type might be presented in 2 different ways:
|
||||
*
|
||||
* - As a nested EIP-712 typed data
|
||||
* - As a _personal_ signature (an EIP-712 mimic of the `eth_personalSign` for a smart contract)
|
||||
*/
|
||||
function isValidSignature(bytes32 hash, bytes calldata signature) public view virtual returns (bytes4 result) {
|
||||
// For the hash `0x7739773977397739773977397739773977397739773977397739773977397739` and an empty signature,
|
||||
// we return the magic value `0x77390001` as it's assumed impossible to find a preimage for it that can be used
|
||||
// maliciously. Useful for simulation purposes and to validate whether the contract supports ERC-7739.
|
||||
return
|
||||
(_isValidNestedTypedDataSignature(hash, signature) || _isValidNestedPersonalSignSignature(hash, signature))
|
||||
? IERC1271.isValidSignature.selector
|
||||
: (hash == 0x7739773977397739773977397739773977397739773977397739773977397739 && signature.length == 0)
|
||||
? bytes4(0x77390001)
|
||||
: bytes4(0xffffffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Nested personal signature verification.
|
||||
*/
|
||||
function _isValidNestedPersonalSignSignature(bytes32 hash, bytes calldata signature) private view returns (bool) {
|
||||
return _rawSignatureValidation(_domainSeparatorV4().toTypedDataHash(hash.personalSignStructHash()), signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Nested EIP-712 typed data verification.
|
||||
*/
|
||||
function _isValidNestedTypedDataSignature(
|
||||
bytes32 hash,
|
||||
bytes calldata encodedSignature
|
||||
) private view returns (bool) {
|
||||
// decode signature
|
||||
(
|
||||
bytes calldata signature,
|
||||
bytes32 appSeparator,
|
||||
bytes32 contentsHash,
|
||||
string calldata contentsDescr
|
||||
) = encodedSignature.decodeTypedDataSig();
|
||||
|
||||
(
|
||||
,
|
||||
string memory name,
|
||||
string memory version,
|
||||
uint256 chainId,
|
||||
address verifyingContract,
|
||||
bytes32 salt,
|
||||
|
||||
) = eip712Domain();
|
||||
|
||||
// Check that contentHash and separator are correct
|
||||
// Rebuild nested hash
|
||||
return
|
||||
hash == appSeparator.toTypedDataHash(contentsHash) &&
|
||||
bytes(contentsDescr).length != 0 &&
|
||||
_rawSignatureValidation(
|
||||
appSeparator.toTypedDataHash(
|
||||
ERC7739Utils.typedDataSignStructHash(
|
||||
contentsDescr,
|
||||
contentsHash,
|
||||
abi.encode(keccak256(bytes(name)), keccak256(bytes(version)), chainId, verifyingContract, salt)
|
||||
)
|
||||
),
|
||||
signature
|
||||
);
|
||||
}
|
||||
}
|
||||
29
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol
generated
vendored
Executable file
29
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol
generated
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/verifiers/ERC7913P256Verifier.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {P256} from "../../../utils/cryptography/P256.sol";
|
||||
import {IERC7913SignatureVerifier} from "../../../interfaces/IERC7913.sol";
|
||||
|
||||
/**
|
||||
* @dev ERC-7913 signature verifier that support P256 (secp256r1) keys.
|
||||
*
|
||||
* @custom:stateless
|
||||
*/
|
||||
contract ERC7913P256Verifier is IERC7913SignatureVerifier {
|
||||
/// @inheritdoc IERC7913SignatureVerifier
|
||||
function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) {
|
||||
// Signature length may be 0x40 or 0x41.
|
||||
if (key.length == 0x40 && signature.length >= 0x40) {
|
||||
bytes32 qx = bytes32(key[0x00:0x20]);
|
||||
bytes32 qy = bytes32(key[0x20:0x40]);
|
||||
bytes32 r = bytes32(signature[0x00:0x20]);
|
||||
bytes32 s = bytes32(signature[0x20:0x40]);
|
||||
if (P256.verify(hash, r, s, qx, qy)) {
|
||||
return IERC7913SignatureVerifier.verify.selector;
|
||||
}
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
23
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol
generated
vendored
Executable file
23
dev/env/node_modules/@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol
generated
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/verifiers/ERC7913RSAVerifier.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {RSA} from "../../../utils/cryptography/RSA.sol";
|
||||
import {IERC7913SignatureVerifier} from "../../../interfaces/IERC7913.sol";
|
||||
|
||||
/**
|
||||
* @dev ERC-7913 signature verifier that support RSA keys.
|
||||
*
|
||||
* @custom:stateless
|
||||
*/
|
||||
contract ERC7913RSAVerifier is IERC7913SignatureVerifier {
|
||||
/// @inheritdoc IERC7913SignatureVerifier
|
||||
function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) {
|
||||
(bytes memory e, bytes memory n) = abi.decode(key, (bytes, bytes));
|
||||
return
|
||||
RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n)
|
||||
? IERC7913SignatureVerifier.verify.selector
|
||||
: bytes4(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
25
dev/env/node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol
generated
vendored
Executable file
25
dev/env/node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol
generated
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.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 {
|
||||
/// @inheritdoc IERC165
|
||||
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
|
||||
return interfaceId == type(IERC165).interfaceId;
|
||||
}
|
||||
}
|
||||
124
dev/env/node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol
generated
vendored
Executable file
124
dev/env/node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol
generated
vendored
Executable file
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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 ("memory-safe") {
|
||||
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
|
||||
returnSize := returndatasize()
|
||||
returnValue := mload(0x00)
|
||||
}
|
||||
|
||||
return success && returnSize >= 0x20 && returnValue > 0;
|
||||
}
|
||||
}
|
||||
25
dev/env/node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol
generated
vendored
Executable file
25
dev/env/node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol
generated
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
|
||||
|
||||
pragma solidity >=0.4.16;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
749
dev/env/node_modules/@openzeppelin/contracts/utils/math/Math.sol
generated
vendored
Executable file
749
dev/env/node_modules/@openzeppelin/contracts/utils/math/Math.sol
generated
vendored
Executable file
@@ -0,0 +1,749 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.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 Return the 512-bit addition of two uint256.
|
||||
*
|
||||
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
|
||||
*/
|
||||
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
|
||||
assembly ("memory-safe") {
|
||||
low := add(a, b)
|
||||
high := lt(low, a)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the 512-bit multiplication of two uint256.
|
||||
*
|
||||
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
|
||||
*/
|
||||
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
|
||||
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
|
||||
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
|
||||
// variables such that product = high * 2²⁵⁶ + low.
|
||||
assembly ("memory-safe") {
|
||||
let mm := mulmod(a, b, not(0))
|
||||
low := mul(a, b)
|
||||
high := sub(sub(mm, low), lt(mm, low))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
|
||||
*/
|
||||
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
uint256 c = a + b;
|
||||
success = c >= a;
|
||||
result = c * SafeCast.toUint(success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
|
||||
*/
|
||||
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
uint256 c = a - b;
|
||||
success = c <= a;
|
||||
result = c * SafeCast.toUint(success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
|
||||
*/
|
||||
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
|
||||
unchecked {
|
||||
uint256 c = a * b;
|
||||
assembly ("memory-safe") {
|
||||
// Only true when the multiplication doesn't overflow
|
||||
// (c / a == b) || (a == 0)
|
||||
success := or(eq(div(c, a), b), iszero(a))
|
||||
}
|
||||
// equivalent to: success ? c : 0
|
||||
result = c * SafeCast.toUint(success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
success = b > 0;
|
||||
assembly ("memory-safe") {
|
||||
// The `DIV` opcode returns zero when the denominator is 0.
|
||||
result := div(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 {
|
||||
success = b > 0;
|
||||
assembly ("memory-safe") {
|
||||
// The `MOD` opcode returns zero when the denominator is 0.
|
||||
result := mod(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
|
||||
*/
|
||||
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
(bool success, uint256 result) = tryAdd(a, b);
|
||||
return ternary(success, result, type(uint256).max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
|
||||
*/
|
||||
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
(, uint256 result) = trySub(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
|
||||
*/
|
||||
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
(bool success, uint256 result) = tryMul(a, b);
|
||||
return ternary(success, result, type(uint256).max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
(uint256 high, uint256 low) = mul512(x, y);
|
||||
|
||||
// Handle non-overflow cases, 256 by 256 division.
|
||||
if (high == 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 low / denominator;
|
||||
}
|
||||
|
||||
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
|
||||
if (denominator <= high) {
|
||||
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// 512 by 256 division.
|
||||
///////////////////////////////////////////////
|
||||
|
||||
// Make division exact by subtracting the remainder from [high low].
|
||||
uint256 remainder;
|
||||
assembly ("memory-safe") {
|
||||
// Compute remainder using mulmod.
|
||||
remainder := mulmod(x, y, denominator)
|
||||
|
||||
// Subtract 256 bit number from 512 bit number.
|
||||
high := sub(high, gt(remainder, low))
|
||||
low := sub(low, 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 ("memory-safe") {
|
||||
// Divide denominator by twos.
|
||||
denominator := div(denominator, twos)
|
||||
|
||||
// Divide [high low] by twos.
|
||||
low := div(low, 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 high into low.
|
||||
low |= high * 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 high
|
||||
// is no longer required.
|
||||
result = low * 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 Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
|
||||
*/
|
||||
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
|
||||
unchecked {
|
||||
(uint256 high, uint256 low) = mul512(x, y);
|
||||
if (high >= 1 << n) {
|
||||
Panic.panic(Panic.UNDER_OVERFLOW);
|
||||
}
|
||||
return (high << (256 - n)) | (low >> n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
|
||||
*/
|
||||
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
|
||||
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 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, except 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 Fermat's little theorem and get the
|
||||
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
|
||||
*/
|
||||
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 Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
|
||||
*
|
||||
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
|
||||
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
|
||||
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
|
||||
*
|
||||
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
|
||||
*/
|
||||
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
|
||||
unchecked {
|
||||
return Math.modExp(a, p - 2, p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 as 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);
|
||||
assembly ("memory-safe") {
|
||||
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);
|
||||
|
||||
assembly ("memory-safe") {
|
||||
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 x) internal pure returns (uint256 r) {
|
||||
// If value has upper 128 bits set, log2 result is at least 128
|
||||
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
|
||||
// If upper 64 bits of 128-bit half set, add 64 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
|
||||
// If upper 32 bits of 64-bit half set, add 32 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
|
||||
// If upper 16 bits of 32-bit half set, add 16 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
|
||||
// If upper 8 bits of 16-bit half set, add 8 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
|
||||
// If upper 4 bits of 8-bit half set, add 4 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
|
||||
|
||||
// Shifts value right by the current result and use it as an index into this lookup table:
|
||||
//
|
||||
// | x (4 bits) | index | table[index] = MSB position |
|
||||
// |------------|---------|-----------------------------|
|
||||
// | 0000 | 0 | table[0] = 0 |
|
||||
// | 0001 | 1 | table[1] = 0 |
|
||||
// | 0010 | 2 | table[2] = 1 |
|
||||
// | 0011 | 3 | table[3] = 1 |
|
||||
// | 0100 | 4 | table[4] = 2 |
|
||||
// | 0101 | 5 | table[5] = 2 |
|
||||
// | 0110 | 6 | table[6] = 2 |
|
||||
// | 0111 | 7 | table[7] = 2 |
|
||||
// | 1000 | 8 | table[8] = 3 |
|
||||
// | 1001 | 9 | table[9] = 3 |
|
||||
// | 1010 | 10 | table[10] = 3 |
|
||||
// | 1011 | 11 | table[11] = 3 |
|
||||
// | 1100 | 12 | table[12] = 3 |
|
||||
// | 1101 | 13 | table[13] = 3 |
|
||||
// | 1110 | 14 | table[14] = 3 |
|
||||
// | 1111 | 15 | table[15] = 3 |
|
||||
//
|
||||
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
|
||||
assembly ("memory-safe") {
|
||||
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 x) internal pure returns (uint256 r) {
|
||||
// If value has upper 128 bits set, log2 result is at least 128
|
||||
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
|
||||
// If upper 64 bits of 128-bit half set, add 64 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
|
||||
// If upper 32 bits of 64-bit half set, add 32 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
|
||||
// If upper 16 bits of 32-bit half set, add 16 to result
|
||||
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
|
||||
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
|
||||
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
1162
dev/env/node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol
generated
vendored
Executable file
1162
dev/env/node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
68
dev/env/node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol
generated
vendored
Executable file
68
dev/env/node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol
generated
vendored
Executable file
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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 `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
|
||||
int256 mask = n >> 255;
|
||||
|
||||
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
|
||||
return uint256((n + mask) ^ mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
dev/env/node_modules/@openzeppelin/contracts/utils/structs/BitMaps.sol
generated
vendored
Executable file
60
dev/env/node_modules/@openzeppelin/contracts/utils/structs/BitMaps.sol
generated
vendored
Executable file
@@ -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;
|
||||
}
|
||||
}
|
||||
630
dev/env/node_modules/@openzeppelin/contracts/utils/structs/Checkpoints.sol
generated
vendored
Executable file
630
dev/env/node_modules/@openzeppelin/contracts/utils/structs/Checkpoints.sol
generated
vendored
Executable file
@@ -0,0 +1,630 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.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 oldValue, uint224 newValue) {
|
||||
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 optimized 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 checkpoints.
|
||||
*/
|
||||
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 oldValue, uint224 newValue) {
|
||||
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) {
|
||||
last._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 first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint208 newValue) {
|
||||
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 optimized 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 checkpoints.
|
||||
*/
|
||||
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 oldValue, uint208 newValue) {
|
||||
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) {
|
||||
last._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 first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint160 newValue) {
|
||||
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 optimized 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 checkpoints.
|
||||
*/
|
||||
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 oldValue, uint160 newValue) {
|
||||
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) {
|
||||
last._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 first (oldest) checkpoint with key strictly bigger 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 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
140
dev/env/node_modules/@openzeppelin/contracts/utils/structs/CircularBuffer.sol
generated
vendored
Executable file
140
dev/env/node_modules/@openzeppelin/contracts/utils/structs/CircularBuffer.sol
generated
vendored
Executable file
@@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/CircularBuffer.sol)
|
||||
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;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library CircularBuffer {
|
||||
/**
|
||||
* @dev Error emitted when trying to setup a buffer with a size of 0.
|
||||
*/
|
||||
error InvalidBufferSize();
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* In a full buffer:
|
||||
* - The most recently pushed item (last) is at data[(index - 1) % data.length]
|
||||
* - The oldest item (first) is at data[index % data.length]
|
||||
*/
|
||||
struct Bytes32CircularBuffer {
|
||||
uint256 _count;
|
||||
bytes32[] _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initialize a new CircularBuffer of a 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 {
|
||||
if (size == 0) revert InvalidBufferSize();
|
||||
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 kept 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;
|
||||
}
|
||||
}
|
||||
156
dev/env/node_modules/@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol
generated
vendored
Executable file
156
dev/env/node_modules/@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol
generated
vendored
Executable file
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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;
|
||||
}
|
||||
}
|
||||
1319
dev/env/node_modules/@openzeppelin/contracts/utils/structs/EnumerableMap.sol
generated
vendored
Executable file
1319
dev/env/node_modules/@openzeppelin/contracts/utils/structs/EnumerableMap.sol
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
792
dev/env/node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol
generated
vendored
Executable file
792
dev/env/node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol
generated
vendored
Executable file
@@ -0,0 +1,792 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.4.0) (utils/structs/EnumerableSet.sol)
|
||||
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Arrays} from "../Arrays.sol";
|
||||
import {Math} from "../math/Math.sol";
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* - Set can be cleared (all elements removed) in O(n).
|
||||
*
|
||||
* ```solidity
|
||||
* contract Example {
|
||||
* // Add the library methods
|
||||
* using EnumerableSet for EnumerableSet.AddressSet;
|
||||
*
|
||||
* // Declare a set state variable
|
||||
* EnumerableSet.AddressSet private mySet;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The following types are supported:
|
||||
*
|
||||
* - `bytes32` (`Bytes32Set`) since v3.3.0
|
||||
* - `address` (`AddressSet`) since v3.3.0
|
||||
* - `uint256` (`UintSet`) since v3.3.0
|
||||
* - `string` (`StringSet`) since v5.4.0
|
||||
* - `bytes` (`BytesSet`) since v5.4.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 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 Removes all the values from a set. O(n).
|
||||
*
|
||||
* WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that
|
||||
* using it may render the function uncallable if the set grows to the point where clearing it consumes too much
|
||||
* gas to fit in a block.
|
||||
*/
|
||||
function _clear(Set storage set) private {
|
||||
uint256 len = _length(set);
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
delete set._positions[set._values[i]];
|
||||
}
|
||||
Arrays.unsafeSetLength(set._values, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return a slice of the 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, uint256 start, uint256 end) private view returns (bytes32[] memory) {
|
||||
unchecked {
|
||||
end = Math.min(end, _length(set));
|
||||
start = Math.min(start, end);
|
||||
|
||||
uint256 len = end - start;
|
||||
bytes32[] memory result = new bytes32[](len);
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
result[i] = Arrays.unsafeAccess(set._values, start + i).value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Removes all the values from a set. O(n).
|
||||
*
|
||||
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||
*/
|
||||
function clear(Bytes32Set storage set) internal {
|
||||
_clear(set._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
assembly ("memory-safe") {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
|
||||
bytes32[] memory store = _values(set._inner, start, end);
|
||||
bytes32[] memory result;
|
||||
|
||||
assembly ("memory-safe") {
|
||||
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 Removes all the values from a set. O(n).
|
||||
*
|
||||
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||
*/
|
||||
function clear(AddressSet storage set) internal {
|
||||
_clear(set._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
assembly ("memory-safe") {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (address[] memory) {
|
||||
bytes32[] memory store = _values(set._inner, start, end);
|
||||
address[] memory result;
|
||||
|
||||
assembly ("memory-safe") {
|
||||
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 Removes all the values from a set. O(n).
|
||||
*
|
||||
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||
*/
|
||||
function clear(UintSet storage set) internal {
|
||||
_clear(set._inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
assembly ("memory-safe") {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return a slice of the 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, uint256 start, uint256 end) internal view returns (uint256[] memory) {
|
||||
bytes32[] memory store = _values(set._inner, start, end);
|
||||
uint256[] memory result;
|
||||
|
||||
assembly ("memory-safe") {
|
||||
result := store
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct StringSet {
|
||||
// Storage of set values
|
||||
string[] _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(string 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(StringSet storage set, string memory value) internal 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(StringSet storage set, string memory value) internal 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) {
|
||||
string memory 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 Removes all the values from a set. O(n).
|
||||
*
|
||||
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||
*/
|
||||
function clear(StringSet storage set) internal {
|
||||
uint256 len = length(set);
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
delete set._positions[set._values[i]];
|
||||
}
|
||||
Arrays.unsafeSetLength(set._values, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set. O(1).
|
||||
*/
|
||||
function contains(StringSet storage set, string memory value) internal view returns (bool) {
|
||||
return set._positions[value] != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of values on the set. O(1).
|
||||
*/
|
||||
function length(StringSet storage set) internal 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(StringSet storage set, uint256 index) internal view returns (string memory) {
|
||||
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(StringSet storage set) internal view returns (string[] memory) {
|
||||
return set._values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return a slice of the 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(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {
|
||||
unchecked {
|
||||
end = Math.min(end, length(set));
|
||||
start = Math.min(start, end);
|
||||
|
||||
uint256 len = end - start;
|
||||
string[] memory result = new string[](len);
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
result[i] = Arrays.unsafeAccess(set._values, start + i).value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
struct BytesSet {
|
||||
// Storage of set values
|
||||
bytes[] _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(bytes 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(BytesSet storage set, bytes memory value) internal 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(BytesSet storage set, bytes memory value) internal 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) {
|
||||
bytes memory 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 Removes all the values from a set. O(n).
|
||||
*
|
||||
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||
*/
|
||||
function clear(BytesSet storage set) internal {
|
||||
uint256 len = length(set);
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
delete set._positions[set._values[i]];
|
||||
}
|
||||
Arrays.unsafeSetLength(set._values, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set. O(1).
|
||||
*/
|
||||
function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {
|
||||
return set._positions[value] != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of values on the set. O(1).
|
||||
*/
|
||||
function length(BytesSet storage set) internal 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(BytesSet storage set, uint256 index) internal view returns (bytes memory) {
|
||||
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(BytesSet storage set) internal view returns (bytes[] memory) {
|
||||
return set._values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return a slice of the 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(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {
|
||||
unchecked {
|
||||
end = Math.min(end, length(set));
|
||||
start = Math.min(start, end);
|
||||
|
||||
uint256 len = end - start;
|
||||
bytes[] memory result = new bytes[](len);
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
result[i] = Arrays.unsafeAccess(set._values, start + i).value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
256
dev/env/node_modules/@openzeppelin/contracts/utils/structs/Heap.sol
generated
vendored
Executable file
256
dev/env/node_modules/@openzeppelin/contracts/utils/structs/Heap.sol
generated
vendored
Executable file
@@ -0,0 +1,256 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/Heap.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
import {SafeCast} from "../math/SafeCast.sol";
|
||||
import {Comparators} from "../Comparators.sol";
|
||||
import {Arrays} from "../Arrays.sol";
|
||||
import {Panic} from "../Panic.sol";
|
||||
import {StorageSlot} from "../StorageSlot.sol";
|
||||
|
||||
/**
|
||||
* @dev Library for managing https://en.wikipedia.org/wiki/Binary_heap[binary heap] that can be used as
|
||||
* https://en.wikipedia.org/wiki/Priority_queue[priority queue].
|
||||
*
|
||||
* Heaps are represented as a tree of values where the first element (index 0) is the root, and where the node at
|
||||
* index i is the child of the node at index (i-1)/2 and the parent of nodes at index 2*i+1 and 2*i+2. Each node
|
||||
* stores an element of the heap.
|
||||
*
|
||||
* The structure is ordered so that each node is bigger than its parent. An immediate consequence is that the
|
||||
* highest priority value is the one at the root. This value can be looked up in constant time (O(1)) at
|
||||
* `heap.tree[0]`
|
||||
*
|
||||
* The structure is designed to perform the following operations with the corresponding complexities:
|
||||
*
|
||||
* * peek (get the highest priority value): O(1)
|
||||
* * insert (insert a value): O(log(n))
|
||||
* * pop (remove the highest priority value): O(log(n))
|
||||
* * replace (replace the highest priority value with a new value): O(log(n))
|
||||
* * length (get the number of elements): O(1)
|
||||
* * clear (remove all elements): O(1)
|
||||
*
|
||||
* IMPORTANT: This library allows for the use of custom comparator functions. Given that manipulating
|
||||
* memory can lead to unexpected behavior. Consider verifying that the comparator does not manipulate
|
||||
* the Heap's state directly and that it follows the Solidity memory safety rules.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library Heap {
|
||||
using Arrays for *;
|
||||
using Math for *;
|
||||
using SafeCast for *;
|
||||
|
||||
/**
|
||||
* @dev Binary heap that supports values of type uint256.
|
||||
*
|
||||
* Each element of that structure uses one storage slot.
|
||||
*/
|
||||
struct Uint256Heap {
|
||||
uint256[] tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Lookup the root element of the heap.
|
||||
*/
|
||||
function peek(Uint256Heap storage self) internal view returns (uint256) {
|
||||
// self.tree[0] will `ARRAY_ACCESS_OUT_OF_BOUNDS` panic if heap is empty.
|
||||
return self.tree[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove (and return) the root element for the heap using the default comparator.
|
||||
*
|
||||
* NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
|
||||
* during the lifecycle of a heap will result in undefined behavior.
|
||||
*/
|
||||
function pop(Uint256Heap storage self) internal returns (uint256) {
|
||||
return pop(self, Comparators.lt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove (and return) the root element for the heap using the provided comparator.
|
||||
*
|
||||
* NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
|
||||
* during the lifecycle of a heap will result in undefined behavior.
|
||||
*/
|
||||
function pop(
|
||||
Uint256Heap storage self,
|
||||
function(uint256, uint256) view returns (bool) comp
|
||||
) internal returns (uint256) {
|
||||
unchecked {
|
||||
uint256 size = length(self);
|
||||
if (size == 0) Panic.panic(Panic.EMPTY_ARRAY_POP);
|
||||
|
||||
// cache
|
||||
uint256 rootValue = self.tree.unsafeAccess(0).value;
|
||||
uint256 lastValue = self.tree.unsafeAccess(size - 1).value;
|
||||
|
||||
// swap last leaf with root, shrink tree and re-heapify
|
||||
self.tree.pop();
|
||||
self.tree.unsafeAccess(0).value = lastValue;
|
||||
_siftDown(self, size - 1, 0, lastValue, comp);
|
||||
|
||||
return rootValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Insert a new element in the heap using the default comparator.
|
||||
*
|
||||
* NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
|
||||
* during the lifecycle of a heap will result in undefined behavior.
|
||||
*/
|
||||
function insert(Uint256Heap storage self, uint256 value) internal {
|
||||
insert(self, value, Comparators.lt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Insert a new element in the heap using the provided comparator.
|
||||
*
|
||||
* NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
|
||||
* during the lifecycle of a heap will result in undefined behavior.
|
||||
*/
|
||||
function insert(
|
||||
Uint256Heap storage self,
|
||||
uint256 value,
|
||||
function(uint256, uint256) view returns (bool) comp
|
||||
) internal {
|
||||
uint256 size = length(self);
|
||||
|
||||
// push new item and re-heapify
|
||||
self.tree.push(value);
|
||||
_siftUp(self, size, value, comp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the root element for the heap, and replace it with a new value, using the default comparator.
|
||||
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
|
||||
*
|
||||
* NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
|
||||
* during the lifecycle of a heap will result in undefined behavior.
|
||||
*/
|
||||
function replace(Uint256Heap storage self, uint256 newValue) internal returns (uint256) {
|
||||
return replace(self, newValue, Comparators.lt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return the root element for the heap, and replace it with a new value, using the provided comparator.
|
||||
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
|
||||
*
|
||||
* NOTE: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
|
||||
* during the lifecycle of a heap will result in undefined behavior.
|
||||
*/
|
||||
function replace(
|
||||
Uint256Heap storage self,
|
||||
uint256 newValue,
|
||||
function(uint256, uint256) view returns (bool) comp
|
||||
) internal returns (uint256) {
|
||||
uint256 size = length(self);
|
||||
if (size == 0) Panic.panic(Panic.EMPTY_ARRAY_POP);
|
||||
|
||||
// cache
|
||||
uint256 oldValue = self.tree.unsafeAccess(0).value;
|
||||
|
||||
// replace and re-heapify
|
||||
self.tree.unsafeAccess(0).value = newValue;
|
||||
_siftDown(self, size, 0, newValue, comp);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of elements in the heap.
|
||||
*/
|
||||
function length(Uint256Heap storage self) internal view returns (uint256) {
|
||||
return self.tree.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Removes all elements in the heap.
|
||||
*/
|
||||
function clear(Uint256Heap storage self) internal {
|
||||
self.tree.unsafeSetLength(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swap node `i` and `j` in the tree.
|
||||
*/
|
||||
function _swap(Uint256Heap storage self, uint256 i, uint256 j) private {
|
||||
StorageSlot.Uint256Slot storage ni = self.tree.unsafeAccess(i);
|
||||
StorageSlot.Uint256Slot storage nj = self.tree.unsafeAccess(j);
|
||||
(ni.value, nj.value) = (nj.value, ni.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Perform heap maintenance on `self`, starting at `index` (with the `value`), using `comp` as a
|
||||
* comparator, and moving toward the leaves of the underlying tree.
|
||||
*
|
||||
* NOTE: This is a private function that is called in a trusted context with already cached parameters. `size`
|
||||
* and `value` could be extracted from `self` and `index`, but that would require redundant storage read. These
|
||||
* parameters are not verified. It is the caller role to make sure the parameters are correct.
|
||||
*/
|
||||
function _siftDown(
|
||||
Uint256Heap storage self,
|
||||
uint256 size,
|
||||
uint256 index,
|
||||
uint256 value,
|
||||
function(uint256, uint256) view returns (bool) comp
|
||||
) private {
|
||||
unchecked {
|
||||
// Check if there is a risk of overflow when computing the indices of the child nodes. If that is the case,
|
||||
// there cannot be child nodes in the tree, so sifting is done.
|
||||
if (index >= type(uint256).max / 2) return;
|
||||
|
||||
// Compute the indices of the potential child nodes
|
||||
uint256 lIndex = 2 * index + 1;
|
||||
uint256 rIndex = 2 * index + 2;
|
||||
|
||||
// Three cases:
|
||||
// 1. Both children exist: sifting may continue on one of the branch (selection required)
|
||||
// 2. Only left child exist: sifting may continue on the left branch (no selection required)
|
||||
// 3. Neither child exist: sifting is done
|
||||
if (rIndex < size) {
|
||||
uint256 lValue = self.tree.unsafeAccess(lIndex).value;
|
||||
uint256 rValue = self.tree.unsafeAccess(rIndex).value;
|
||||
if (comp(lValue, value) || comp(rValue, value)) {
|
||||
uint256 cIndex = comp(lValue, rValue).ternary(lIndex, rIndex);
|
||||
_swap(self, index, cIndex);
|
||||
_siftDown(self, size, cIndex, value, comp);
|
||||
}
|
||||
} else if (lIndex < size) {
|
||||
uint256 lValue = self.tree.unsafeAccess(lIndex).value;
|
||||
if (comp(lValue, value)) {
|
||||
_swap(self, index, lIndex);
|
||||
_siftDown(self, size, lIndex, value, comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Perform heap maintenance on `self`, starting at `index` (with the `value`), using `comp` as a
|
||||
* comparator, and moving toward the root of the underlying tree.
|
||||
*
|
||||
* NOTE: This is a private function that is called in a trusted context with already cached parameters. `value`
|
||||
* could be extracted from `self` and `index`, but that would require redundant storage read. These parameters are not
|
||||
* verified. It is the caller role to make sure the parameters are correct.
|
||||
*/
|
||||
function _siftUp(
|
||||
Uint256Heap storage self,
|
||||
uint256 index,
|
||||
uint256 value,
|
||||
function(uint256, uint256) view returns (bool) comp
|
||||
) private {
|
||||
unchecked {
|
||||
while (index > 0) {
|
||||
uint256 parentIndex = (index - 1) / 2;
|
||||
uint256 parentValue = self.tree.unsafeAccess(parentIndex).value;
|
||||
if (comp(parentValue, value)) break;
|
||||
_swap(self, index, parentIndex);
|
||||
index = parentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
267
dev/env/node_modules/@openzeppelin/contracts/utils/structs/MerkleTree.sol
generated
vendored
Executable file
267
dev/env/node_modules/@openzeppelin/contracts/utils/structs/MerkleTree.sol
generated
vendored
Executable file
@@ -0,0 +1,267 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/MerkleTree.sol)
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Hashes} from "../cryptography/Hashes.sol";
|
||||
import {Arrays} from "../Arrays.sol";
|
||||
import {Panic} from "../Panic.sol";
|
||||
import {StorageSlot} from "../StorageSlot.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. Defaults to {Hashes-commutativeKeccak256}.
|
||||
*
|
||||
* NOTE: Building trees using non-commutative hashing functions (i.e. `H(a, b) != H(b, a)`) is supported. However,
|
||||
* proving the inclusion of a leaf in such trees is not possible with the {MerkleProof} library since it only supports
|
||||
* _commutative_ hashing functions.
|
||||
*
|
||||
* _Available since v5.1._
|
||||
*/
|
||||
library MerkleTree {
|
||||
/// @dev Error emitted when trying to update a leaf that was not previously pushed.
|
||||
error MerkleTreeUpdateInvalidIndex(uint256 index, uint256 length);
|
||||
|
||||
/// @dev Error emitted when the proof used during an update is invalid (could not reproduce the side).
|
||||
error MerkleTreeUpdateInvalidProof();
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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**treeDepth`.
|
||||
*
|
||||
* Calling this function on MerkleTree that was already setup and used will reset it to a blank state.
|
||||
*
|
||||
* Once a tree is setup, any push to it must use the same hashing function. This means that values
|
||||
* should be pushed to it using the default {xref-MerkleTree-push-struct-MerkleTree-Bytes32PushTree-bytes32-}[push] function.
|
||||
*
|
||||
* 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 treeDepth, bytes32 zero) internal returns (bytes32 initialRoot) {
|
||||
return setup(self, treeDepth, zero, Hashes.commutativeKeccak256);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[setup], but allows to specify a custom hashing function.
|
||||
*
|
||||
* Once a tree is setup, any push to it must use the same hashing function. This means that values
|
||||
* should be pushed to it using the custom push function, which should be the same one as used during the setup.
|
||||
*
|
||||
* IMPORTANT: Providing a custom hashing function is a security-sensitive operation since it may
|
||||
* compromise the soundness of the tree.
|
||||
*
|
||||
* NOTE: Consider verifying that the hashing function does not manipulate the memory state directly and that it
|
||||
* follows the Solidity memory safety rules. Otherwise, it may lead to unexpected behavior.
|
||||
*/
|
||||
function setup(
|
||||
Bytes32PushTree storage self,
|
||||
uint8 treeDepth,
|
||||
bytes32 zero,
|
||||
function(bytes32, bytes32) view returns (bytes32) fnHash
|
||||
) internal returns (bytes32 initialRoot) {
|
||||
// Store depth in the dynamic array
|
||||
Arrays.unsafeSetLength(self._sides, treeDepth);
|
||||
Arrays.unsafeSetLength(self._zeros, treeDepth);
|
||||
|
||||
// Build each root of zero-filled subtrees
|
||||
bytes32 currentZero = zero;
|
||||
for (uint256 i = 0; i < treeDepth; ++i) {
|
||||
Arrays.unsafeAccess(self._zeros, i).value = currentZero;
|
||||
currentZero = fnHash(currentZero, currentZero);
|
||||
}
|
||||
|
||||
// Set the first root
|
||||
self._nextLeafIndex = 0;
|
||||
|
||||
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.
|
||||
*
|
||||
* This variant uses {Hashes-commutativeKeccak256} to hash internal nodes. It should only be used on merkle trees
|
||||
* that were setup using the same (default) hashing function (i.e. by calling
|
||||
* {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[the default setup] function).
|
||||
*/
|
||||
function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) {
|
||||
return push(self, leaf, Hashes.commutativeKeccak256);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* This variant uses a custom hashing function to hash internal nodes. It should only be called with the same
|
||||
* function as the one used during the initial setup of the merkle tree.
|
||||
*/
|
||||
function push(
|
||||
Bytes32PushTree storage self,
|
||||
bytes32 leaf,
|
||||
function(bytes32, bytes32) view returns (bytes32) fnHash
|
||||
) internal returns (uint256 index, bytes32 newRoot) {
|
||||
// Cache read
|
||||
uint256 treeDepth = depth(self);
|
||||
|
||||
// Get leaf index
|
||||
index = self._nextLeafIndex++;
|
||||
|
||||
// Check if tree is full.
|
||||
if (index >= 1 << treeDepth) {
|
||||
Panic.panic(Panic.RESOURCE_ERROR);
|
||||
}
|
||||
|
||||
// Rebuild branch from leaf to root
|
||||
uint256 currentIndex = index;
|
||||
bytes32 currentLevelHash = leaf;
|
||||
for (uint256 i = 0; i < treeDepth; 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 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 Change the value of the leaf at position `index` from `oldValue` to `newValue`. Returns the recomputed "old"
|
||||
* root (before the update) and "new" root (after the update). The caller must verify that the reconstructed old
|
||||
* root is the last known one.
|
||||
*
|
||||
* The `proof` must be an up-to-date inclusion proof for the leaf being updated. This means that this function is
|
||||
* vulnerable to front-running. Any {push} or {update} operation (that changes the root of the tree) would render
|
||||
* all "in flight" updates invalid.
|
||||
*
|
||||
* This variant uses {Hashes-commutativeKeccak256} to hash internal nodes. It should only be used on merkle trees
|
||||
* that were setup using the same (default) hashing function (i.e. by calling
|
||||
* {xref-MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-}[the default setup] function).
|
||||
*/
|
||||
function update(
|
||||
Bytes32PushTree storage self,
|
||||
uint256 index,
|
||||
bytes32 oldValue,
|
||||
bytes32 newValue,
|
||||
bytes32[] memory proof
|
||||
) internal returns (bytes32 oldRoot, bytes32 newRoot) {
|
||||
return update(self, index, oldValue, newValue, proof, Hashes.commutativeKeccak256);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Change the value of the leaf at position `index` from `oldValue` to `newValue`. Returns the recomputed "old"
|
||||
* root (before the update) and "new" root (after the update). The caller must verify that the reconstructed old
|
||||
* root is the last known one.
|
||||
*
|
||||
* The `proof` must be an up-to-date inclusion proof for the leaf being update. This means that this function is
|
||||
* vulnerable to front-running. Any {push} or {update} operation (that changes the root of the tree) would render
|
||||
* all "in flight" updates invalid.
|
||||
*
|
||||
* This variant uses a custom hashing function to hash internal nodes. It should only be called with the same
|
||||
* function as the one used during the initial setup of the merkle tree.
|
||||
*/
|
||||
function update(
|
||||
Bytes32PushTree storage self,
|
||||
uint256 index,
|
||||
bytes32 oldValue,
|
||||
bytes32 newValue,
|
||||
bytes32[] memory proof,
|
||||
function(bytes32, bytes32) view returns (bytes32) fnHash
|
||||
) internal returns (bytes32 oldRoot, bytes32 newRoot) {
|
||||
unchecked {
|
||||
// Check index range
|
||||
uint256 length = self._nextLeafIndex;
|
||||
if (index >= length) revert MerkleTreeUpdateInvalidIndex(index, length);
|
||||
|
||||
// Cache read
|
||||
uint256 treeDepth = depth(self);
|
||||
|
||||
// Workaround stack too deep
|
||||
bytes32[] storage sides = self._sides;
|
||||
|
||||
// This cannot overflow because: 0 <= index < length
|
||||
uint256 lastIndex = length - 1;
|
||||
uint256 currentIndex = index;
|
||||
bytes32 currentLevelHashOld = oldValue;
|
||||
bytes32 currentLevelHashNew = newValue;
|
||||
for (uint32 i = 0; i < treeDepth; i++) {
|
||||
bool isLeft = currentIndex % 2 == 0;
|
||||
|
||||
lastIndex >>= 1;
|
||||
currentIndex >>= 1;
|
||||
|
||||
if (isLeft && currentIndex == lastIndex) {
|
||||
StorageSlot.Bytes32Slot storage side = Arrays.unsafeAccess(sides, i);
|
||||
if (side.value != currentLevelHashOld) revert MerkleTreeUpdateInvalidProof();
|
||||
side.value = currentLevelHashNew;
|
||||
}
|
||||
|
||||
bytes32 sibling = proof[i];
|
||||
currentLevelHashOld = fnHash(
|
||||
isLeft ? currentLevelHashOld : sibling,
|
||||
isLeft ? sibling : currentLevelHashOld
|
||||
);
|
||||
currentLevelHashNew = fnHash(
|
||||
isLeft ? currentLevelHashNew : sibling,
|
||||
isLeft ? sibling : currentLevelHashNew
|
||||
);
|
||||
}
|
||||
return (currentLevelHashOld, currentLevelHashNew);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tree's depth (set at initialization)
|
||||
*/
|
||||
function depth(Bytes32PushTree storage self) internal view returns (uint256) {
|
||||
return self._zeros.length;
|
||||
}
|
||||
}
|
||||
133
dev/env/node_modules/@openzeppelin/contracts/utils/types/Time.sol
generated
vendored
Executable file
133
dev/env/node_modules/@openzeppelin/contracts/utils/types/Time.sol
generated
vendored
Executable file
@@ -0,0 +1,133 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v5.1.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 valueBefore, uint32 valueAfter, uint48 effect) {
|
||||
(valueBefore, valueAfter, 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 valueBefore, uint32 valueAfter, uint48 effect) {
|
||||
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