diff --git a/README.md b/README.md index 94b7920a..3a305336 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Solidity modules and utilities that **go far beyond mediocre solidity**. - Implementation of the [**Contracts Registry**](https://eips.ethereum.org/EIPS/eip-6224) pattern - State-of-the-art cryptography primitives (**ECDSA over 256-bit and 384-bit curves**, **RSASSA-PSS**) - Advanced data structures (**Vector**, **DynamicSet**, **PriorityQueue**, **AVLTree**) -- ZK-friendly [**Sparse Merkle Tree**](https://docs.iden3.io/publications/pdfs/Merkle-Tree.pdf) and [**Incremental Merkle Tree**](https://github.com/runtimeverification/deposit-contract-verification/blob/master/deposit-contract-verification.pdf) implementations +- ZK-friendly **Cartesian Merkle Tree**, [**Sparse Merkle Tree**](https://docs.iden3.io/publications/pdfs/Merkle-Tree.pdf), and [**Incremental Merkle Tree**](https://github.com/runtimeverification/deposit-contract-verification/blob/master/deposit-contract-verification.pdf) implementations - Versatile access control smart contracts (**Merkle whitelists**, **RBAC**) - Enhanced and simplified [**Diamond**](https://eips.ethereum.org/EIPS/eip-2535) pattern - Flexible finance instruments (**Staking**, **Vesting**) diff --git a/contracts/libs/data-structures/CartesianMerkleTree.sol b/contracts/libs/data-structures/CartesianMerkleTree.sol new file mode 100644 index 00000000..58595941 --- /dev/null +++ b/contracts/libs/data-structures/CartesianMerkleTree.sol @@ -0,0 +1,965 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +/** + * @notice Cartesian Merkle Tree Module + * + * A magnificent ZK-friendly data structure based on a Binary Search Tree + Heap + Merkle Tree. Short names: CMT, Treaple. + * Possesses deterministic and idemponent properties. Can be used as a substitute for a Sparse Merkle Tree (SMT). + * + * Gas usage for adding and removing 5,000 elements to a CMT with the keccak256 and poseidon hash functions is detailed below: + * + * Keccak256: + * - CMT.add - 249k + * - CMT.remove - 181k + * + * Poseidon: + * - CMT.add - 896k + * - CMT.remove - 746k + * + * ## Usage Example: + * + * ```solidity + * using CartesianMerkleTree for CartesianMerkleTree.UintCMT; + * + * CartesianMerkleTree.UintCMT internal uintTreaple; + * ... + * uintTreaple.initialize(80); + * + * uintTreaple.add(100); + * + * uintTreaple.getRoot(); + * + * CartesianMerkleTree.Proof memory proof = uintTreaple.getProof(100); + * + * uintTreaple.getNodeByKey(100); + * + * uintTreaple.remove(100); + * ``` + */ +library CartesianMerkleTree { + /** + ********************* + * UintCMT * + ********************* + */ + + struct UintCMT { + CMT _treaple; + } + + /** + * @notice The function to initialize the Cartesian Merkle tree. + * Under the hood it sets the desired proof size of the CMT proofs, therefore can be considered + * alias function for the `setDesiredProofSize`. + * + * Requirements: + * - The desired proof size value must be greater than 0. + * + * @param treaple self. + * @param desiredProofSize_ The desired proof size of the CMT proofs. + */ + function initialize(UintCMT storage treaple, uint32 desiredProofSize_) internal { + _initialize(treaple._treaple, desiredProofSize_); + } + + /** + * @notice The function to set a custom hash function, that will be used to build the Cartesian Merkle Tree. + * + * Requirements: + * - The tree must be empty. + * + * @param treaple self. + * @param hash3_ The hash function that accepts three arguments. + */ + function setHasher( + UintCMT storage treaple, + function(bytes32, bytes32, bytes32) view returns (bytes32) hash3_ + ) internal { + _setHasher(treaple._treaple, hash3_); + } + + /** + * @notice The function to set a desired proof size, that will be used to build the Cartesian Merkle Tree proofs. + * + * Requirements: + * - The desired proof size value must be greater than 0. + * + * @param treaple self. + * @param desiredProofSize_ The desired proof size of the CMT proofs. + */ + function setDesiredProofSize(UintCMT storage treaple, uint32 desiredProofSize_) internal { + _setDesiredProofSize(treaple._treaple, desiredProofSize_); + } + + /** + * @notice The function to add a new element to the uint256 treaple. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + */ + function add(UintCMT storage treaple, uint256 key_) internal { + _add(treaple._treaple, bytes32(key_)); + } + + /** + * @notice The function to remove an element from the uint256 treaple. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + */ + function remove(UintCMT storage treaple, uint256 key_) internal { + _remove(treaple._treaple, bytes32(key_)); + } + + /** + * @notice The function to get the proof if a node with specific key exists or not exists in the CMT. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + * @param desiredProofSize_ The desired siblings length in the proof. + * @return CMT proof struct. + */ + function getProof( + UintCMT storage treaple, + uint256 key_, + uint32 desiredProofSize_ + ) internal view returns (Proof memory) { + return _proof(treaple._treaple, bytes32(key_), desiredProofSize_); + } + + /** + * @notice The function to get the root of the Cartesian Merkle Tree. + * Complexity is O(1). + * + * @param treaple self. + * @return The root of the Cartesian Merkle Tree. + */ + function getRoot(UintCMT storage treaple) internal view returns (bytes32) { + return _rootMerkleHash(treaple._treaple); + } + + /** + * @notice The function to get the node by its index. + * Complexity is O(1). + * + * @param treaple self. + * @param nodeId_ The index of the node. + * @return The node. + */ + function getNode( + UintCMT storage treaple, + uint256 nodeId_ + ) internal view returns (Node memory) { + return _node(treaple._treaple, nodeId_); + } + + /** + * @notice The function to get the node by its key. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + * @return The node. + */ + function getNodeByKey( + UintCMT storage treaple, + uint256 key_ + ) internal view returns (Node memory) { + return _nodeByKey(treaple._treaple, bytes32(key_)); + } + + /** + * @notice The function to get the desired proof size value. + * + * @param treaple self. + * @return The desired proof size value. + */ + function getDesiredProofSize(UintCMT storage treaple) internal view returns (uint256) { + return _desiredProofSize(treaple._treaple); + } + + /** + * @notice The function to get the number of nodes in the Cartesian Merkle Tree. + * + * @param treaple self. + * @return The number of nodes in the Cartesian Merkle Tree. + */ + function getNodesCount(UintCMT storage treaple) internal view returns (uint64) { + return uint64(_nodesCount(treaple._treaple)); + } + + /** + * @notice The function to check if custom hash function is set. + * + * @param treaple self. + * @return True if custom hash function is set, otherwise false. + */ + function isCustomHasherSet(UintCMT storage treaple) internal view returns (bool) { + return _isCustomHasherSet(treaple._treaple); + } + + /** + ********************** + * Bytes32CMT * + ********************** + */ + + struct Bytes32CMT { + CMT _treaple; + } + + /** + * @notice The function to initialize the Cartesian Merkle tree. + * Under the hood it sets the desired proof size of the CMT proofs, therefore can be considered + * alias function for the `setDesiredProofSize`. + * + * Requirements: + * - The desired proof size value must be greater than 0. + * + * @param treaple self. + * @param desiredProofSize_ The desired proof size of the CMT proofs. + */ + function initialize(Bytes32CMT storage treaple, uint32 desiredProofSize_) internal { + _initialize(treaple._treaple, desiredProofSize_); + } + + /** + * @notice The function to set a custom hash function, that will be used to build the Cartesian Merkle Tree. + * + * Requirements: + * - The tree must be empty. + * + * @param treaple self. + * @param hash3_ The hash function that accepts three arguments. + */ + function setHasher( + Bytes32CMT storage treaple, + function(bytes32, bytes32, bytes32) view returns (bytes32) hash3_ + ) internal { + _setHasher(treaple._treaple, hash3_); + } + + /** + * @notice The function to set a desired proof size, that will be used to build the Cartesian Merkle Tree proofs. + * + * Requirements: + * - The desired proof size value must be greater than 0. + * + * @param treaple self. + * @param desiredProofSize_ The desired proof size of the CMT proofs. + */ + function setDesiredProofSize(Bytes32CMT storage treaple, uint32 desiredProofSize_) internal { + _setDesiredProofSize(treaple._treaple, desiredProofSize_); + } + + /** + * @notice The function to add a new element to the bytes32 treaple. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + */ + function add(Bytes32CMT storage treaple, bytes32 key_) internal { + _add(treaple._treaple, key_); + } + + /** + * @notice The function to remove an element from the bytes32 treaple. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + */ + function remove(Bytes32CMT storage treaple, bytes32 key_) internal { + _remove(treaple._treaple, key_); + } + + /** + * @notice The function to get the proof if a node with specific key exists or not exists in the CMT. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + * @param desiredProofSize_ The desired siblings length in the proof. + * @return CMT proof struct. + */ + function getProof( + Bytes32CMT storage treaple, + bytes32 key_, + uint32 desiredProofSize_ + ) internal view returns (Proof memory) { + return _proof(treaple._treaple, key_, desiredProofSize_); + } + + /** + * @notice The function to get the root of the Cartesian Merkle Tree. + * Complexity is O(1). + * + * @param treaple self. + * @return The root of the Cartesian Merkle Tree. + */ + function getRoot(Bytes32CMT storage treaple) internal view returns (bytes32) { + return _rootMerkleHash(treaple._treaple); + } + + /** + * @notice The function to get the node by its index. + * Complexity is O(1). + * + * @param treaple self. + * @param nodeId_ The index of the node. + * @return The node. + */ + function getNode( + Bytes32CMT storage treaple, + uint256 nodeId_ + ) internal view returns (Node memory) { + return _node(treaple._treaple, nodeId_); + } + + /** + * @notice The function to get the node by its key. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + * @return The node. + */ + function getNodeByKey( + Bytes32CMT storage treaple, + bytes32 key_ + ) internal view returns (Node memory) { + return _nodeByKey(treaple._treaple, key_); + } + + /** + * @notice The function to get the desired proof size value. + * + * @param treaple self. + * @return The desired proof size value. + */ + function getDesiredProofSize(Bytes32CMT storage treaple) internal view returns (uint256) { + return _desiredProofSize(treaple._treaple); + } + + /** + * @notice The function to get the number of nodes in the Cartesian Merkle Tree. + * + * @param treaple self. + * @return The number of nodes in the Cartesian Merkle Tree. + */ + function getNodesCount(Bytes32CMT storage treaple) internal view returns (uint64) { + return uint64(_nodesCount(treaple._treaple)); + } + + /** + * @notice The function to check if custom hash function is set. + * + * @param treaple self. + * @return True if custom hash function is set, otherwise false. + */ + function isCustomHasherSet(Bytes32CMT storage treaple) internal view returns (bool) { + return _isCustomHasherSet(treaple._treaple); + } + + /** + ************************ + * AddressCMT * + ************************ + */ + + struct AddressCMT { + CMT _treaple; + } + + /** + * @notice The function to initialize the Cartesian Merkle tree. + * Under the hood it sets the desired proof size of the CMT proofs, therefore can be considered + * alias function for the `setDesiredProofSize`. + * + * Requirements: + * - The desired proof size value must be greater than 0. + * + * @param treaple self. + * @param desiredProofSize_ The desired proof size of the CMT proofs. + */ + function initialize(AddressCMT storage treaple, uint32 desiredProofSize_) internal { + _initialize(treaple._treaple, desiredProofSize_); + } + + /** + * @notice The function to set a custom hash function, that will be used to build the Cartesian Merkle Tree. + * + * Requirements: + * - The tree must be empty. + * + * @param treaple self. + * @param hash3_ The hash function that accepts three arguments. + */ + function setHasher( + AddressCMT storage treaple, + function(bytes32, bytes32, bytes32) view returns (bytes32) hash3_ + ) internal { + _setHasher(treaple._treaple, hash3_); + } + + /** + * @notice The function to set a desired proof size, that will be used to build the Cartesian Merkle Tree proofs. + * + * Requirements: + * - The desired proof size value must be greater than 0. + * + * @param treaple self. + * @param desiredProofSize_ The desired proof size of the CMT proofs. + */ + function setDesiredProofSize(AddressCMT storage treaple, uint32 desiredProofSize_) internal { + _setDesiredProofSize(treaple._treaple, desiredProofSize_); + } + + /** + * @notice The function to add a new element to the address treaple. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + */ + function add(AddressCMT storage treaple, address key_) internal { + _add(treaple._treaple, _fromAddressToBytes32(key_)); + } + + /** + * @notice The function to remove an element from the address treaple. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + */ + function remove(AddressCMT storage treaple, address key_) internal { + _remove(treaple._treaple, _fromAddressToBytes32(key_)); + } + + /** + * @notice The function to get the proof if a node with specific key exists or not exists in the CMT. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + * @param desiredProofSize_ The desired siblings length in the proof. + * @return CMT proof struct. + */ + function getProof( + AddressCMT storage treaple, + address key_, + uint32 desiredProofSize_ + ) internal view returns (Proof memory) { + return _proof(treaple._treaple, _fromAddressToBytes32(key_), desiredProofSize_); + } + + /** + * @notice The function to get the root of the Cartesian Merkle Tree. + * Complexity is O(1). + * + * @param treaple self. + * @return The root of the Cartesian Merkle Tree. + */ + function getRoot(AddressCMT storage treaple) internal view returns (bytes32) { + return _rootMerkleHash(treaple._treaple); + } + + /** + * @notice The function to get the node by its index. + * Complexity is O(1). + * + * @param treaple self. + * @param nodeId_ The index of the node. + * @return The node. + */ + function getNode( + AddressCMT storage treaple, + uint256 nodeId_ + ) internal view returns (Node memory) { + return _node(treaple._treaple, nodeId_); + } + + /** + * @notice The function to get the node by its key. + * Complexity is O(log(n)), where n is the max depth of the treaple. + * + * @param treaple self. + * @param key_ The key of the element. + * @return The node. + */ + function getNodeByKey( + AddressCMT storage treaple, + address key_ + ) internal view returns (Node memory) { + return _nodeByKey(treaple._treaple, _fromAddressToBytes32(key_)); + } + + /** + * @notice The function to get the desired proof size value. + * + * @param treaple self. + * @return The desired proof size value. + */ + function getDesiredProofSize(AddressCMT storage treaple) internal view returns (uint256) { + return _desiredProofSize(treaple._treaple); + } + + /** + * @notice The function to get the number of nodes in the Cartesian Merkle Tree. + * + * @param treaple self. + * @return The number of nodes in the Cartesian Merkle Tree. + */ + function getNodesCount(AddressCMT storage treaple) internal view returns (uint64) { + return uint64(_nodesCount(treaple._treaple)); + } + + /** + * @notice The function to check if custom hash function is set. + * + * @param treaple self. + * @return True if custom hash function is set, otherwise false. + */ + function isCustomHasherSet(AddressCMT storage treaple) internal view returns (bool) { + return _isCustomHasherSet(treaple._treaple); + } + + function _fromAddressToBytes32(address key_) private pure returns (bytes32 result_) { + assembly { + result_ := key_ + } + } + + /** + ************************ + * InnerCMT * + ************************ + */ + + /** + * @notice Defines the structure of the Cartesian Merkle Tree. + * + * @param nodes A mapping of the treaple's nodes, where the key is the node's index, starting from 1 upon node addition. + * + * @param merkleRootId The index of the root node. + * @param nodesCount The total number of nodes within the Cartesian Merkle Tree. + * @param deletedNodesCount The total number of the deleted nodes within the Cartesian Merkle Tree. + * @param desiredProofSize The desired proof size of the CMT proofs. + * @param isCustomHasherSet Indicates whether custom hash function has been configured (true) or not (false). + * @param hash3 A hash function accepting three arguments. + */ + struct CMT { + mapping(uint64 => Node) nodes; + uint64 merkleRootId; + uint64 nodesCount; + uint64 deletedNodesCount; + uint32 desiredProofSize; + bool isCustomHasherSet; + function(bytes32, bytes32, bytes32) view returns (bytes32) hash3; + } + + /** + * @notice Describes a node within the Cartesian Merkle tree, including its children, hash, priority and key. + * + * @param childLeft The index of the left child node. + * @param childRight The index of the right child node. + * @param priority The priority of the node that counts as `keccak256(key)` + * @param merkleHash The hash of the node, calculated as follows: + * - H(k || child1 || child2) where k is the current node key; + * child1 and child2 are merkleHash values of child nodes that were sorted in ascending order + * + * @param key The key associated with the node. + */ + struct Node { + uint64 childLeft; + uint64 childRight; + bytes16 priority; + bytes32 merkleHash; + bytes32 key; + } + + /** + * @notice Represents the proof of a node's (non-)existence within the Cartesian Merkle tree. + * + * @param root The root hash of the Cartesian Merkle tree. + * @param siblings An array of sibling hashes can be used to get the Cartesian Merkle Root. + * @param siblingsLength The number of siblings to be used for evidence. + * @param existence Indicates the presence (true) or absence (false) of the node. + * @param key The key associated with the node. + * @param nonExistenceKey The non-existence key of the auxiliary node in case when existence is false. + */ + struct Proof { + bytes32 root; + bytes32[] siblings; + uint256 siblingsLength; + bool existence; + bytes32 key; + bytes32 nonExistenceKey; + } + + bytes32 internal constant ZERO_HASH = bytes32(0); + + modifier onlyInitialized(CMT storage treaple) { + require(_isInitialized(treaple), "CartesianMerkleTree: treaple is not initialized"); + _; + } + + function _initialize(CMT storage treaple, uint32 desiredProofSize_) private { + require(!_isInitialized(treaple), "CartesianMerkleTree: treaple is already initialized"); + + _setDesiredProofSize(treaple, desiredProofSize_); + } + + function _setDesiredProofSize(CMT storage treaple, uint32 desiredProofSize_) private { + require( + desiredProofSize_ > 0, + "CartesianMerkleTree: desired proof size must be greater than zero" + ); + + treaple.desiredProofSize = desiredProofSize_; + } + + function _setHasher( + CMT storage treaple, + function(bytes32, bytes32, bytes32) view returns (bytes32) hash3_ + ) private { + require(_nodesCount(treaple) == 0, "CartesianMerkleTree: treaple is not empty"); + + treaple.isCustomHasherSet = true; + + treaple.hash3 = hash3_; + } + + function _add(CMT storage treaple, bytes32 key_) private onlyInitialized(treaple) { + require(key_ != 0, "CartesianMerkleTree: the key can't be zero"); + + treaple.merkleRootId = uint64(_add(treaple, treaple.merkleRootId, key_)); + } + + function _remove(CMT storage treaple, bytes32 key_) private onlyInitialized(treaple) { + require(key_ != 0, "CartesianMerkleTree: the key can't be zero"); + + treaple.merkleRootId = uint64(_remove(treaple, treaple.merkleRootId, key_)); + } + + function _add( + CMT storage treaple, + uint256 rootNodeId_, + bytes32 key_ + ) private returns (uint256) { + Node storage rootNode = treaple.nodes[uint64(rootNodeId_)]; + + if (rootNode.key == 0) { + return _newNode(treaple, key_); + } + + require(rootNode.key != key_, "CartesianMerkleTree: the key already exists"); + + if (rootNode.key > key_) { + rootNode.childLeft = uint64(_add(treaple, rootNode.childLeft, key_)); + + if (treaple.nodes[rootNode.childLeft].priority > rootNode.priority) { + rootNodeId_ = _rightRotate(treaple, rootNodeId_); + rootNode = treaple.nodes[uint64(rootNodeId_)]; + } + } else { + rootNode.childRight = uint64(_add(treaple, rootNode.childRight, key_)); + + if (treaple.nodes[rootNode.childRight].priority > rootNode.priority) { + rootNodeId_ = _leftRotate(treaple, rootNodeId_); + rootNode = treaple.nodes[uint64(rootNodeId_)]; + } + } + + rootNode.merkleHash = _hashNodes(treaple, rootNodeId_); + + return rootNodeId_; + } + + function _remove( + CMT storage treaple, + uint256 rootNodeId_, + bytes32 key_ + ) private returns (uint256) { + Node storage rootNode = treaple.nodes[uint64(rootNodeId_)]; + + require(rootNode.key != 0, "CartesianMerkleTree: the node does not exist"); + + if (key_ < rootNode.key) { + rootNode.childLeft = uint64(_remove(treaple, rootNode.childLeft, key_)); + } else if (key_ > rootNode.key) { + rootNode.childRight = uint64(_remove(treaple, rootNode.childRight, key_)); + } + + if (rootNode.key == key_) { + Node storage leftRootChildNode = treaple.nodes[rootNode.childLeft]; + Node storage rightRootChildNode = treaple.nodes[rootNode.childRight]; + + if (leftRootChildNode.key == 0 || rightRootChildNode.key == 0) { + uint64 nodeIdToRemove_ = uint64(rootNodeId_); + + rootNodeId_ = leftRootChildNode.key == 0 + ? rootNode.childRight + : rootNode.childLeft; + + treaple.deletedNodesCount++; + delete treaple.nodes[nodeIdToRemove_]; + } else if (leftRootChildNode.priority < rightRootChildNode.priority) { + rootNodeId_ = _leftRotate(treaple, rootNodeId_); + rootNode = treaple.nodes[uint64(rootNodeId_)]; + + rootNode.childLeft = uint64(_remove(treaple, rootNode.childLeft, key_)); + } else { + rootNodeId_ = _rightRotate(treaple, rootNodeId_); + rootNode = treaple.nodes[uint64(rootNodeId_)]; + + rootNode.childRight = uint64(_remove(treaple, rootNode.childRight, key_)); + } + } + + rootNode.merkleHash = _hashNodes(treaple, rootNodeId_); + + return rootNodeId_; + } + + function _rightRotate(CMT storage treaple, uint256 nodeId_) private returns (uint256) { + Node storage node = treaple.nodes[uint64(nodeId_)]; + + uint64 leftId_ = node.childLeft; + + Node storage leftNode = treaple.nodes[leftId_]; + + uint64 leftRightId_ = leftNode.childRight; + + leftNode.childRight = uint64(nodeId_); + node.childLeft = leftRightId_; + + node.merkleHash = _hashNodes(treaple, nodeId_); + + return leftId_; + } + + function _leftRotate(CMT storage treaple, uint256 nodeId_) private returns (uint256) { + Node storage node = treaple.nodes[uint64(nodeId_)]; + + uint64 rightId_ = node.childRight; + + Node storage rightNode = treaple.nodes[rightId_]; + + uint64 rightLeftId_ = rightNode.childLeft; + + rightNode.childLeft = uint64(nodeId_); + node.childRight = rightLeftId_; + + node.merkleHash = _hashNodes(treaple, nodeId_); + + return rightId_; + } + + function _proof( + CMT storage treaple, + bytes32 key_, + uint256 desiredProofSize_ + ) private view returns (Proof memory) { + desiredProofSize_ = desiredProofSize_ == 0 + ? _desiredProofSize(treaple) + : desiredProofSize_; + + Proof memory proof_ = Proof({ + root: _rootMerkleHash(treaple), + siblings: new bytes32[](desiredProofSize_), + siblingsLength: 0, + existence: false, + key: key_, + nonExistenceKey: ZERO_HASH + }); + + if (treaple.merkleRootId == 0) { + return proof_; + } + + Node storage node; + uint256 currentSiblingsIndex_; + uint256 nextNodeId_ = treaple.merkleRootId; + + while (true) { + node = treaple.nodes[uint64(nextNodeId_)]; + + if (node.key == key_) { + _addProofSibling( + proof_, + currentSiblingsIndex_++, + treaple.nodes[node.childLeft].merkleHash + ); + _addProofSibling( + proof_, + currentSiblingsIndex_++, + treaple.nodes[node.childRight].merkleHash + ); + + proof_.existence = true; + proof_.siblingsLength = currentSiblingsIndex_; + + break; + } + + uint64 otherNodeId_; + + if (node.key > key_) { + otherNodeId_ = node.childRight; + nextNodeId_ = node.childLeft; + } else { + otherNodeId_ = node.childLeft; + nextNodeId_ = node.childRight; + } + + if (nextNodeId_ == 0) { + _addProofSibling( + proof_, + currentSiblingsIndex_++, + treaple.nodes[node.childLeft].merkleHash + ); + _addProofSibling( + proof_, + currentSiblingsIndex_++, + treaple.nodes[node.childRight].merkleHash + ); + + proof_.nonExistenceKey = node.key; + proof_.siblingsLength = currentSiblingsIndex_; + + break; + } + + _addProofSibling(proof_, currentSiblingsIndex_++, node.key); + _addProofSibling( + proof_, + currentSiblingsIndex_++, + treaple.nodes[otherNodeId_].merkleHash + ); + } + + return proof_; + } + + function _newNode(CMT storage treaple, bytes32 key_) private returns (uint256) { + uint64 nodeId_ = ++treaple.nodesCount; + + treaple.nodes[nodeId_] = Node({ + childLeft: 0, + childRight: 0, + priority: bytes16(keccak256(abi.encodePacked(key_))), + merkleHash: _getNodesHash(treaple, key_, 0, 0), + key: key_ + }); + + return nodeId_; + } + + function _addProofSibling( + Proof memory proof_, + uint256 currentSiblingsIndex_, + bytes32 siblingToAdd_ + ) private pure { + require( + currentSiblingsIndex_ < proof_.siblings.length, + "CartesianMerkleTree: desired proof size is too low" + ); + + proof_.siblings[currentSiblingsIndex_] = siblingToAdd_; + } + + function _hashNodes(CMT storage treaple, uint256 nodeId_) private view returns (bytes32) { + Node storage node = treaple.nodes[uint64(nodeId_)]; + + bytes32 leftHash_ = treaple.nodes[node.childLeft].merkleHash; + bytes32 rightHash_ = treaple.nodes[node.childRight].merkleHash; + + if (leftHash_ > rightHash_) { + (leftHash_, rightHash_) = (rightHash_, leftHash_); + } + + return _getNodesHash(treaple, node.key, leftHash_, rightHash_); + } + + function _getNodesHash( + CMT storage treaple, + bytes32 nodeKey_, + bytes32 leftNodeKey_, + bytes32 rightNodeKey_ + ) private view returns (bytes32) { + function(bytes32, bytes32, bytes32) view returns (bytes32) hash3_ = treaple + .isCustomHasherSet + ? treaple.hash3 + : _hash3; + + return hash3_(nodeKey_, leftNodeKey_, rightNodeKey_); + } + + function _nodeByKey( + CMT storage treaple, + bytes32 key_ + ) private view returns (Node memory result_) { + uint256 nextNodeId_ = treaple.merkleRootId; + + Node storage currentNode; + + while (true) { + currentNode = treaple.nodes[uint64(nextNodeId_)]; + + if (currentNode.key == 0) { + break; + } + + if (currentNode.key == key_) { + result_ = currentNode; + + break; + } + + nextNodeId_ = currentNode.key < key_ ? currentNode.childRight : currentNode.childLeft; + } + } + + function _hash3(bytes32 a_, bytes32 b_, bytes32 c) private pure returns (bytes32 result_) { + assembly { + let freePtr_ := mload(64) + + mstore(freePtr_, a_) + mstore(add(freePtr_, 32), b_) + mstore(add(freePtr_, 64), c) + + result_ := keccak256(freePtr_, 96) + } + } + + function _rootMerkleHash(CMT storage treaple) private view returns (bytes32) { + return treaple.nodes[treaple.merkleRootId].merkleHash; + } + + function _node(CMT storage treaple, uint256 nodeId_) private view returns (Node memory) { + return treaple.nodes[uint64(nodeId_)]; + } + + function _desiredProofSize(CMT storage treaple) private view returns (uint256) { + return treaple.desiredProofSize; + } + + function _nodesCount(CMT storage treaple) private view returns (uint256) { + return treaple.nodesCount - treaple.deletedNodesCount; + } + + function _isInitialized(CMT storage treaple) private view returns (bool) { + return treaple.desiredProofSize > 0; + } + + function _isCustomHasherSet(CMT storage treaple) private view returns (bool) { + return treaple.isCustomHasherSet; + } +} diff --git a/contracts/libs/data-structures/SparseMerkleTree.sol b/contracts/libs/data-structures/SparseMerkleTree.sol index d5acf940..7a8164f3 100644 --- a/contracts/libs/data-structures/SparseMerkleTree.sol +++ b/contracts/libs/data-structures/SparseMerkleTree.sol @@ -233,7 +233,7 @@ library SparseMerkleTree { /** ********************** - * Bytes32IMT * + * Bytes32SMT * ********************** */ @@ -1048,27 +1048,27 @@ library SparseMerkleTree { return proof_; } - function _hash2(bytes32 a, bytes32 b) private pure returns (bytes32 result) { + function _hash2(bytes32 a_, bytes32 b_) private pure returns (bytes32 result_) { assembly { - mstore(0, a) - mstore(32, b) + mstore(0, a_) + mstore(32, b_) - result := keccak256(0, 64) + result_ := keccak256(0, 64) } } /** * @dev The decision not to update the free memory pointer is due to the temporary nature of the hash arguments. */ - function _hash3(bytes32 a, bytes32 b, bytes32 c) private pure returns (bytes32 result) { + function _hash3(bytes32 a_, bytes32 b_, bytes32 c) private pure returns (bytes32 result_) { assembly { - let free_ptr := mload(64) + let freePtr_ := mload(64) - mstore(free_ptr, a) - mstore(add(free_ptr, 32), b) - mstore(add(free_ptr, 64), c) + mstore(freePtr_, a_) + mstore(add(freePtr_, 32), b_) + mstore(add(freePtr_, 64), c) - result := keccak256(free_ptr, 96) + result_ := keccak256(freePtr_, 96) } } diff --git a/contracts/mock/libs/data-structures/CartesianMerkleTreeMock.sol b/contracts/mock/libs/data-structures/CartesianMerkleTreeMock.sol new file mode 100644 index 00000000..1e177905 --- /dev/null +++ b/contracts/mock/libs/data-structures/CartesianMerkleTreeMock.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {CartesianMerkleTree} from "../../../libs/data-structures/CartesianMerkleTree.sol"; + +library PoseidonUnit3L { + function poseidon(uint256[3] calldata) public pure returns (uint256) {} +} + +contract CartesianMerkleTreeMock { + using CartesianMerkleTree for *; + + CartesianMerkleTree.UintCMT internal _uintCMT; + CartesianMerkleTree.Bytes32CMT internal _bytes32CMT; + CartesianMerkleTree.AddressCMT internal _addressCMT; + + function initializeUintTreaple(uint32 maxDepth_) external { + _uintCMT.initialize(maxDepth_); + } + + function initializeBytes32Treaple(uint32 maxDepth_) external { + _bytes32CMT.initialize(maxDepth_); + } + + function initializeAddressTreaple(uint32 maxDepth_) external { + _addressCMT.initialize(maxDepth_); + } + + function setDesiredProofSizeUintTreaple(uint32 maxDepth_) external { + _uintCMT.setDesiredProofSize(maxDepth_); + } + + function setDesiredProofSizeBytes32Treaple(uint32 maxDepth_) external { + _bytes32CMT.setDesiredProofSize(maxDepth_); + } + + function setDesiredProofSizeAddressTreaple(uint32 maxDepth_) external { + _addressCMT.setDesiredProofSize(maxDepth_); + } + + function setUintPoseidonHasher() external { + _uintCMT.setHasher(_hash3); + } + + function setBytes32PoseidonHasher() external { + _bytes32CMT.setHasher(_hash3); + } + + function setAddressPoseidonHasher() external { + _addressCMT.setHasher(_hash3); + } + + function addUint(uint256 key_) external { + _uintCMT.add(key_); + } + + function removeUint(uint256 key_) external { + _uintCMT.remove(key_); + } + + function addBytes32(bytes32 key_) external { + _bytes32CMT.add(key_); + } + + function removeBytes32(bytes32 key_) external { + _bytes32CMT.remove(key_); + } + + function addAddress(address key_) external { + _addressCMT.add(key_); + } + + function removeAddress(address key_) external { + _addressCMT.remove(key_); + } + + function getUintProof( + uint256 key_, + uint32 desiredProofSize_ + ) external view returns (CartesianMerkleTree.Proof memory) { + return _uintCMT.getProof(key_, desiredProofSize_); + } + + function getBytes32Proof( + bytes32 key_, + uint32 desiredProofSize_ + ) external view returns (CartesianMerkleTree.Proof memory) { + return _bytes32CMT.getProof(key_, desiredProofSize_); + } + + function getAddressProof( + address key_, + uint32 desiredProofSize_ + ) external view returns (CartesianMerkleTree.Proof memory) { + return _addressCMT.getProof(key_, desiredProofSize_); + } + + function getUintRoot() external view returns (bytes32) { + return _uintCMT.getRoot(); + } + + function getBytes32Root() external view returns (bytes32) { + return _bytes32CMT.getRoot(); + } + + function getAddressRoot() external view returns (bytes32) { + return _addressCMT.getRoot(); + } + + function getUintNode(uint256 nodeId_) external view returns (CartesianMerkleTree.Node memory) { + return _uintCMT.getNode(nodeId_); + } + + function getBytes32Node( + uint256 nodeId_ + ) external view returns (CartesianMerkleTree.Node memory) { + return _bytes32CMT.getNode(nodeId_); + } + + function getAddressNode( + uint256 nodeId_ + ) external view returns (CartesianMerkleTree.Node memory) { + return _addressCMT.getNode(nodeId_); + } + + function getUintNodeByKey( + uint256 key_ + ) external view returns (CartesianMerkleTree.Node memory) { + return _uintCMT.getNodeByKey(key_); + } + + function getBytes32NodeByKey( + bytes32 key_ + ) external view returns (CartesianMerkleTree.Node memory) { + return _bytes32CMT.getNodeByKey(key_); + } + + function getAddressNodeByKey( + address key_ + ) external view returns (CartesianMerkleTree.Node memory) { + return _addressCMT.getNodeByKey(key_); + } + + function getUintDesiredProofSize() external view returns (uint256) { + return _uintCMT.getDesiredProofSize(); + } + + function getBytes32DesiredProofSize() external view returns (uint256) { + return _bytes32CMT.getDesiredProofSize(); + } + + function getAddressDesiredProofSize() external view returns (uint256) { + return _addressCMT.getDesiredProofSize(); + } + + function getUintNodesCount() external view returns (uint256) { + return _uintCMT.getNodesCount(); + } + + function getBytes32NodesCount() external view returns (uint256) { + return _bytes32CMT.getNodesCount(); + } + + function getAddressNodesCount() external view returns (uint256) { + return _addressCMT.getNodesCount(); + } + + function isUintCustomHasherSet() external view returns (bool) { + return _uintCMT.isCustomHasherSet(); + } + + function isBytes32CustomHasherSet() external view returns (bool) { + return _bytes32CMT.isCustomHasherSet(); + } + + function isAddressCustomHasherSet() external view returns (bool) { + return _addressCMT.isCustomHasherSet(); + } + + function hash3( + bytes32 element1_, + bytes32 element2_, + bytes32 element3_ + ) external pure returns (bytes32) { + return _hash3(element1_, element2_, element3_); + } + + function _hash3( + bytes32 element1_, + bytes32 element2_, + bytes32 element3_ + ) internal pure returns (bytes32) { + return + bytes32( + PoseidonUnit3L.poseidon( + [uint256(element1_), uint256(element2_), uint256(element3_)] + ) + ); + } +} diff --git a/hardhat.config.ts b/hardhat.config.ts index cc70cc4a..7bed7690 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -55,7 +55,7 @@ const config: HardhatUserConfig = { contractSizer: { alphaSort: false, disambiguatePaths: false, - runOnCompile: true, + // runOnCompile: true, strict: false, }, gasReporter: { diff --git a/package-lock.json b/package-lock.json index 9856a9b3..7d3fdd7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@solarity/solidity-lib", - "version": "2.7.13", + "version": "2.7.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@solarity/solidity-lib", - "version": "2.7.13", + "version": "2.7.14", "license": "MIT", "dependencies": { "@openzeppelin/contracts": "4.9.6", @@ -18,38 +18,37 @@ }, "devDependencies": { "@iden3/js-crypto": "^1.1.0", - "@iden3/js-merkletree": "^1.2.0", - "@metamask/eth-sig-util": "^7.0.3", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.7", - "@nomicfoundation/hardhat-ethers": "^3.0.6", - "@nomicfoundation/hardhat-network-helpers": "^1.0.10", + "@iden3/js-merkletree": "^1.3.1", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.8", + "@nomicfoundation/hardhat-ethers": "^3.0.8", + "@nomicfoundation/hardhat-network-helpers": "^1.0.12", "@solarity/hardhat-markup": "^1.0.8", "@typechain/ethers-v6": "^0.5.1", "@typechain/hardhat": "^9.1.0", "@types/chai": "^4.3.16", - "@types/mocha": "^10.0.7", + "@types/mocha": "^10.0.10", "@types/node": "^18.16.0", "bignumber.js": "^9.1.2", - "chai": "^4.4.1", + "chai": "^4.5.0", "circomlibjs": "^0.1.7", - "dotenv": "^16.4.5", - "ethers": "^6.13.1", + "dotenv": "^16.4.7", + "ethers": "^6.13.4", "hardhat": "^2.22.0", "hardhat-contract-sizer": "^2.10.0", - "hardhat-gas-reporter": "^2.2.0", - "husky": "^9.0.11", + "hardhat-gas-reporter": "^2.2.2", + "husky": "^9.1.7", "merkletreejs": "^0.4.0", - "mocha": "^10.6.0", + "mocha": "^11.0.1", "mock-local-storage": "^1.1.24", - "prettier": "^3.3.3", - "prettier-plugin-solidity": "^1.3.1", - "solhint": "^5.0.1", + "prettier": "^3.4.2", + "prettier-plugin-solidity": "^1.4.1", + "solhint": "^5.0.3", "solhint-plugin-prettier": "^0.1.0", - "solidity-coverage": "^0.8.12", + "solidity-coverage": "^0.8.14", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", "typechain": "^8.3.2", - "typescript": "^5.5.3" + "typescript": "^5.7.0" } }, "node_modules/@adraffy/ens-normalize": { @@ -103,16 +102,6 @@ "node": ">=12" } }, - "node_modules/@ethereumjs/common": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", - "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", - "dev": true, - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "crc-32": "^1.2.0" - } - }, "node_modules/@ethereumjs/rlp": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", @@ -125,21 +114,6 @@ "node": ">=14" } }, - "node_modules/@ethereumjs/tx": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", - "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", - "dev": true, - "dependencies": { - "@ethereumjs/common": "^3.2.0", - "@ethereumjs/rlp": "^4.0.1", - "@ethereumjs/util": "^8.1.0", - "ethereum-cryptography": "^2.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/@ethereumjs/util": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", @@ -154,6 +128,69 @@ "node": ">=14" } }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, "node_modules/@ethersproject/abi": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", @@ -1028,96 +1065,71 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@metamask/abi-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@metamask/abi-utils/-/abi-utils-2.0.4.tgz", - "integrity": "sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ==", + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", "dev": true, "dependencies": { - "@metamask/superstruct": "^3.1.0", - "@metamask/utils": "^9.0.0" + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=12.0.0" } }, - "node_modules/@metamask/eth-sig-util": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-7.0.3.tgz", - "integrity": "sha512-PAtGnOkYvh90k2lEZldq/FK7GTLF6WxE+2bV85PoA3pqlJnmJCAY62tuvxHSwnVngSKlc4mcNvjnUg2eYO6JGg==", + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", "dev": true, "dependencies": { - "@ethereumjs/util": "^8.1.0", - "@metamask/abi-utils": "^2.0.4", - "@metamask/utils": "^9.0.0", - "@scure/base": "~1.1.3", - "ethereum-cryptography": "^2.1.2", - "tweetnacl": "^1.0.3" - }, - "engines": { - "node": "^16.20 || ^18.16 || >=20" + "@types/node": "*" } }, - "node_modules/@metamask/superstruct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.1.0.tgz", - "integrity": "sha512-N08M56HdOgBfRKkrgCMZvQppkZGcArEop3kixNEtVbJKm6P9Cfg0YkI6X0s1g78sNrj2fWUwvJADdZuzJgFttA==", - "dev": true, - "engines": { - "node": ">=16.0.0" - } + "node_modules/@metamask/eth-sig-util/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true }, - "node_modules/@metamask/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", "dev": true, "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" } }, "node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "dev": true, "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" + "@noble/hashes": "1.3.2" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/hashes": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz", - "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", "dev": true, "engines": { - "node": "^14.21.3 || >=16" + "node": ">= 16" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -1295,29 +1307,6 @@ } } }, - "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, "node_modules/@nomicfoundation/ethereumjs-util": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", @@ -1339,29 +1328,6 @@ } } }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, "node_modules/@nomicfoundation/hardhat-chai-matchers": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz", @@ -1577,51 +1543,27 @@ } }, "node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.2.tgz", + "integrity": "sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==", "dev": true, "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" + "@noble/curves": "~1.2.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.2" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", "dev": true, "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -1831,6 +1773,18 @@ "prettier": ">=2.3.0" } }, + "node_modules/@solarity/hardhat-markup/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@solidity-parser/parser": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", @@ -1927,15 +1881,6 @@ "@types/chai": "*" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -1970,16 +1915,10 @@ "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", "dev": true }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", - "dev": true - }, "node_modules/@types/node": { - "version": "18.19.67", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.67.tgz", - "integrity": "sha512-wI8uHusga+0ZugNp0Ol/3BqQfEcCCNfojtO6Oou9iVNGPTL6QNSdnUdqq85fRgIorLhLMuPIKpsN98QE9Nh+KQ==", + "version": "18.19.68", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.68.tgz", + "integrity": "sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -2426,9 +2365,9 @@ } }, "node_modules/axios": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", - "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -2698,16 +2637,15 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -2716,9 +2654,22 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "engines": { @@ -3171,18 +3122,6 @@ } } }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -3303,9 +3242,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -3486,9 +3425,9 @@ "dev": true }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, "engines": { "node": ">=12" @@ -3497,6 +3436,20 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3622,13 +3575,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -3777,30 +3727,41 @@ "@noble/hashes": "^1.4.0" } }, - "node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "node_modules/ethereum-bloom-filters/node_modules/@noble/hashes": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz", + "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==", "dev": true, "engines": { - "node": ">= 16" + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" } }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, "node_modules/ethereumjs-abi": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", @@ -3827,29 +3788,6 @@ "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "dev": true }, - "node_modules/ethereumjs-abi/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", @@ -3881,29 +3819,6 @@ "node": ">=10.0.0" } }, - "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, "node_modules/ethers": { "version": "6.13.4", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.4.tgz", @@ -3932,30 +3847,6 @@ "node": ">=14.0.0" } }, - "node_modules/ethers/node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/ethers/node_modules/@types/node": { "version": "22.7.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", @@ -4294,16 +4185,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.5.tgz", + "integrity": "sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -4584,13 +4478,10 @@ } }, "node_modules/gopd": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz", - "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" }, @@ -4660,14 +4551,14 @@ } }, "node_modules/hardhat": { - "version": "2.22.16", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.16.tgz", - "integrity": "sha512-d52yQZ09u0roL6GlgJSvtknsBtIuj9JrJ/U8VMzr/wue+gO5v2tQayvOX6llerlR57Zw2EOTQjLAt6RpHvjwHA==", + "version": "2.22.17", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.17.tgz", + "integrity": "sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.6.4", + "@nomicfoundation/edr": "^0.6.5", "@nomicfoundation/ethereumjs-common": "4.0.4", "@nomicfoundation/ethereumjs-tx": "5.0.4", "@nomicfoundation/ethereumjs-util": "9.0.4", @@ -4766,20 +4657,67 @@ "hardhat": "^2.16.0" } }, - "node_modules/hardhat/node_modules/@metamask/eth-sig-util": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", - "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "node_modules/hardhat-gas-reporter/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", "dev": true, "dependencies": { - "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^6.2.1", - "ethjs-util": "^0.1.6", - "tweetnacl": "^1.0.3", - "tweetnacl-util": "^0.15.1" + "@noble/hashes": "1.4.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, "engines": { - "node": ">=12.0.0" + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat-gas-reporter/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" } }, "node_modules/hardhat/node_modules/@noble/hashes": { @@ -4827,12 +4765,6 @@ "@scure/base": "~1.1.0" } }, - "node_modules/hardhat/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "dev": true - }, "node_modules/hardhat/node_modules/ethereum-cryptography": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", @@ -4845,65 +4777,38 @@ "@scure/bip39": "1.1.1" } }, - "node_modules/hardhat/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "dev": true, - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/hardhat/node_modules/ethereumjs-util/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "node_modules/hardhat/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "dependencies": { - "@types/node": "*" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" } }, - "node_modules/hardhat/node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "node_modules/hardhat/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/hardhat/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/hardhat/node_modules/jsonfile": { @@ -4915,13 +4820,102 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/hardhat/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/hardhat/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hardhat/node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, "bin": { - "semver": "bin/semver.js" + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/hardhat/node_modules/mocha/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/hardhat/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/hardhat/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/hardhat/node_modules/universalify": { @@ -4933,15 +4927,6 @@ "node": ">= 4.0.0" } }, - "node_modules/hardhat/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/hardhat/node_modules/ws": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", @@ -4994,12 +4979,12 @@ } }, "node_modules/has-proto": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.1.0.tgz", - "integrity": "sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.7" + "dunder-proto": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -5009,9 +4994,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -5318,12 +5303,15 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5589,12 +5577,14 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.0.tgz", + "integrity": "sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "call-bind": "^1.0.7", + "has-symbols": "^1.0.3", + "safe-regex-test": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -6158,9 +6148,9 @@ } }, "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz", + "integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", @@ -6170,7 +6160,7 @@ "diff": "^5.2.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", - "glob": "^8.1.0", + "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", @@ -6189,7 +6179,7 @@ "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha/node_modules/chokidar": { @@ -6216,26 +6206,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -6546,6 +6516,18 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, + "node_modules/package-json/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6695,15 +6677,6 @@ "node": ">=4" } }, - "node_modules/pony-cause": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", - "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -6723,9 +6696,9 @@ } }, "node_modules/prettier": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", - "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -6771,6 +6744,18 @@ "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", "dev": true }, + "node_modules/prettier-plugin-solidity/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -6964,18 +6949,19 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz", - "integrity": "sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz", + "integrity": "sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", + "dunder-proto": "^1.0.0", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "which-builtin-type": "^1.1.4" + "gopd": "^1.2.0", + "which-builtin-type": "^1.2.0" }, "engines": { "node": ">= 0.4" @@ -7401,15 +7387,12 @@ "dev": true }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/serialize-javascript": { @@ -7767,6 +7750,18 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/solhint/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/solidity-ast": { "version": "0.4.55", "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.55.tgz", @@ -7841,6 +7836,39 @@ "node": ">=4" } }, + "node_modules/solidity-coverage/node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/solidity-coverage/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/solidity-coverage/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -7856,15 +7884,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/solidity-coverage/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/solidity-coverage/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -7879,13 +7898,24 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/solidity-coverage/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/solidity-coverage/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/solidity-coverage/node_modules/jsonfile": { @@ -7897,6 +7927,92 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/solidity-coverage/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/solidity-coverage/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/solidity-coverage/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/solidity-coverage/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/solidity-coverage/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -7909,6 +8025,15 @@ "node": ">=4" } }, + "node_modules/solidity-coverage/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/solidity-coverage/node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -8151,9 +8276,9 @@ } }, "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -8763,14 +8888,10 @@ "dev": true }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], "bin": { "uuid": "dist/bin/uuid" } @@ -8817,57 +8938,6 @@ "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", "dev": true }, - "node_modules/viem/node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/bip32": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.2.tgz", - "integrity": "sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==", - "dev": true, - "dependencies": { - "@noble/curves": "~1.2.0", - "@noble/hashes": "~1.3.2", - "@scure/base": "~1.1.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/bip39": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", - "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", - "dev": true, - "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/viem/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", @@ -8929,6 +8999,69 @@ "node": ">=8.0.0" } }, + "node_modules/web3-utils/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8945,16 +9078,19 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.0.tgz", + "integrity": "sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==", "dev": true, "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.0", + "is-number-object": "^1.1.0", + "is-string": "^1.1.0", + "is-symbol": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" diff --git a/package.json b/package.json index 6f30ecd9..f0f71464 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@solarity/solidity-lib", - "version": "2.7.13", + "version": "2.7.14", "license": "MIT", "author": "Distributed Lab", "readme": "README.md", @@ -43,37 +43,36 @@ }, "devDependencies": { "@iden3/js-crypto": "^1.1.0", - "@iden3/js-merkletree": "^1.2.0", - "@metamask/eth-sig-util": "^7.0.3", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.7", - "@nomicfoundation/hardhat-ethers": "^3.0.6", - "@nomicfoundation/hardhat-network-helpers": "^1.0.10", + "@iden3/js-merkletree": "^1.3.1", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.8", + "@nomicfoundation/hardhat-ethers": "^3.0.8", + "@nomicfoundation/hardhat-network-helpers": "^1.0.12", "@solarity/hardhat-markup": "^1.0.8", "@typechain/ethers-v6": "^0.5.1", "@typechain/hardhat": "^9.1.0", "@types/chai": "^4.3.16", - "@types/mocha": "^10.0.7", + "@types/mocha": "^10.0.10", "@types/node": "^18.16.0", "bignumber.js": "^9.1.2", - "chai": "^4.4.1", - "ethers": "^6.13.1", + "chai": "^4.5.0", + "ethers": "^6.13.4", "circomlibjs": "^0.1.7", - "dotenv": "^16.4.5", + "dotenv": "^16.4.7", "hardhat": "^2.22.0", "hardhat-contract-sizer": "^2.10.0", - "hardhat-gas-reporter": "^2.2.0", - "husky": "^9.0.11", + "hardhat-gas-reporter": "^2.2.2", + "husky": "^9.1.7", "merkletreejs": "^0.4.0", - "mocha": "^10.6.0", + "mocha": "^11.0.1", "mock-local-storage": "^1.1.24", - "prettier": "^3.3.3", - "prettier-plugin-solidity": "^1.3.1", - "solhint": "^5.0.1", + "prettier": "^3.4.2", + "prettier-plugin-solidity": "^1.4.1", + "solhint": "^5.0.3", "solhint-plugin-prettier": "^0.1.0", - "solidity-coverage": "^0.8.12", + "solidity-coverage": "^0.8.14", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", "typechain": "^8.3.2", - "typescript": "^5.5.3" + "typescript": "^5.7.0" } } diff --git a/test/libs/data-structures/CartesianMerkleTree.test.ts b/test/libs/data-structures/CartesianMerkleTree.test.ts new file mode 100644 index 00000000..f97db3df --- /dev/null +++ b/test/libs/data-structures/CartesianMerkleTree.test.ts @@ -0,0 +1,591 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { BytesLike } from "ethers"; + +import { CartesianMerkleTreeMock } from "@ethers-v6"; + +import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; + +import { Reverter } from "@/test/helpers/reverter"; +import { ZERO_BYTES32 } from "@/scripts/utils/constants"; +import { getPoseidon, poseidonHash } from "@/test/helpers/poseidon-hash"; + +import { CartesianMerkleTree } from "@/generated-types/ethers/contracts/mock/libs/data-structures/CartesianMerkleTreeMock"; + +describe("CartesianMerkleTree", () => { + const reverter = new Reverter(); + + let USER1: SignerWithAddress; + + let treaple: CartesianMerkleTreeMock; + + function createRandomArray(length: number, bytesCount: number = 32): string[] { + const resultArr: string[] = []; + + for (let i = 0; i < length; i++) { + resultArr.push(ethers.hexlify(ethers.randomBytes(bytesCount))); + } + + return resultArr; + } + + async function verifyCMTProof( + proof: CartesianMerkleTree.ProofStruct, + expectedRoot: string, + keyToVerify: string, + expectedExistence: boolean = true, + isPoseidonHash: boolean = false, + ) { + expect(proof.existence).to.be.eq(expectedExistence); + + keyToVerify = `0x${keyToVerify.slice(2).padStart(64, "0")}`; + + keyToVerify = proof.existence ? keyToVerify.toString() : proof.nonExistenceKey.toString(); + + let currentSiblingsIndex: number = Number(proof.siblingsLength); + let finalHash: string = ""; + + while (true) { + let valuesToHash: string[] = []; + let currentSiblings: BytesLike[] = proof.siblings.slice(currentSiblingsIndex - 2, currentSiblingsIndex); + + if (currentSiblingsIndex === Number(proof.siblingsLength)) { + if (BigInt(ethers.hexlify(currentSiblings[0])) > BigInt(ethers.hexlify(currentSiblings[1]))) { + currentSiblings = [currentSiblings[1], currentSiblings[0]]; + } + + valuesToHash = [keyToVerify, ethers.hexlify(currentSiblings[0]), ethers.hexlify(currentSiblings[1])]; + } else { + let sortedChildren: string[] = [finalHash, ethers.hexlify(currentSiblings[1])]; + + if (BigInt(sortedChildren[0]) > BigInt(sortedChildren[1])) { + sortedChildren = [sortedChildren[1], sortedChildren[0]]; + } + + valuesToHash = [currentSiblings[0].toString(), sortedChildren[0], sortedChildren[1]]; + } + + let nodeHash: string = ""; + + if (isPoseidonHash) { + nodeHash = await treaple.hash3(valuesToHash[0], valuesToHash[1], valuesToHash[2]); + } else { + nodeHash = ethers.solidityPackedKeccak256(["bytes32", "bytes32", "bytes32"], valuesToHash); + } + + finalHash = nodeHash; + currentSiblingsIndex -= 2; + + if (currentSiblingsIndex <= 0) { + break; + } + } + + expect(expectedRoot).to.be.eq(finalHash); + } + + function shuffle(array: any): any { + let currentIndex = array.length; + + while (currentIndex != 0) { + let randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + + [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]; + } + } + + before("setup", async () => { + [USER1] = await ethers.getSigners(); + + const CartesianMerkleTreeMock = await ethers.getContractFactory("CartesianMerkleTreeMock", { + libraries: { + PoseidonUnit3L: await (await getPoseidon(3)).getAddress(), + }, + }); + + treaple = await CartesianMerkleTreeMock.deploy(); + + await reverter.snapshot(); + }); + + afterEach("cleanup", async () => { + await reverter.revert(); + }); + + describe("Uint CMT", () => { + beforeEach("setup", async () => { + await treaple.initializeUintTreaple(40); + await treaple.setUintPoseidonHasher(); + }); + + it("should not initialize twice", async () => { + await expect(treaple.initializeUintTreaple(20)).to.be.rejectedWith( + "CartesianMerkleTree: treaple is already initialized", + ); + }); + + it("should revert if trying to set incorrect desired proof size", async () => { + await expect(treaple.setDesiredProofSizeUintTreaple(0)).to.be.rejectedWith( + "CartesianMerkleTree: desired proof size must be greater than zero", + ); + }); + + it("should correctly set new desired proof size", async () => { + await treaple.setDesiredProofSizeUintTreaple(20); + + expect(await treaple.getUintDesiredProofSize()).to.equal(20); + }); + + it("should revert if trying to call add/remove functions on non-initialized treaple", async () => { + const CartesianMerkleTreeMock = await ethers.getContractFactory("CartesianMerkleTreeMock", { + libraries: { + PoseidonUnit3L: await (await getPoseidon(3)).getAddress(), + }, + }); + const newTreap = await CartesianMerkleTreeMock.deploy(); + + await expect(newTreap.addUint(13n)).to.be.rejectedWith("CartesianMerkleTree: treaple is not initialized"); + await expect(newTreap.removeUint(13n)).to.be.rejectedWith("CartesianMerkleTree: treaple is not initialized"); + }); + + it("should add and full remove elements from the CMT correctly", async () => { + const keysCount: number = 20; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keysCount; i++) { + await treaple.addUint(keys[i]); + } + + shuffle(keys); + + for (let i = 0; i < keysCount; i++) { + await treaple.removeUint(keys[i]); + } + + expect(await treaple.getUintRoot()).to.equal(ZERO_BYTES32); + + expect(await treaple.getUintNodesCount()).to.equal(0); + + expect(await treaple.isUintCustomHasherSet()).to.be.true; + expect(treaple.setUintPoseidonHasher()).to.not.be.rejected; + }); + + it("should maintain deterministic property", async () => { + const keysCount: number = 100; + const keys: string[] = createRandomArray(keysCount); + + const CartesianMerkleTreeMock = await ethers.getContractFactory("CartesianMerkleTreeMock", { + libraries: { + PoseidonUnit3L: await (await getPoseidon(3)).getAddress(), + }, + }); + + let treapleRoot: string = ""; + + for (let i = 0; i < 5; i++) { + const tmpTreaple = await CartesianMerkleTreeMock.deploy(); + await tmpTreaple.initializeUintTreaple(40); + + for (let i = 0; i < keysCount; i++) { + await tmpTreaple.addUint(keys[i]); + } + + if (i == 0) { + treapleRoot = await tmpTreaple.getUintRoot(); + } + + expect(treapleRoot).to.be.eq(await tmpTreaple.getUintRoot()); + + shuffle(keys); + } + }); + + it("should maintain idempotence", async () => { + const keysCount: number = 30; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keysCount; i++) { + await treaple.addUint(keys[i]); + } + + const treapleRoot: string = await treaple.getUintRoot(); + const usedIndexes: number[] = []; + + for (let i = 0; i < 10; i++) { + let randIndex: number = -1; + + while (true) { + const newRandIndex = + Math.floor(Math.random() * (Number(await treaple.getUintNodesCount()) + usedIndexes.length - 1)) + 1; + + if (!usedIndexes.includes(newRandIndex)) { + randIndex = newRandIndex; + usedIndexes.push(newRandIndex); + + break; + } + } + + let currentNode = await treaple.getUintNode(randIndex); + + await treaple.removeUint(currentNode.key); + + expect(await treaple.getUintRoot()).to.be.not.eq(treapleRoot); + + await treaple.addUint(currentNode.key); + + expect(await treaple.getUintRoot()).to.be.eq(treapleRoot); + } + }); + + it("should not remove non-existent leaves", async () => { + const keys = [7n, 1n, 5n]; + + for (let key of keys) { + const hexKey = ethers.toBeHex(key, 32); + + await treaple.addUint(hexKey); + } + + await expect(treaple.removeUint(ethers.toBeHex(8, 32))).to.be.revertedWith( + "CartesianMerkleTree: the node does not exist", + ); + }); + + it("should generate empty proof on empty tree", async () => { + const desiredProofSize = 20; + const proof = await treaple.getUintProof(ethers.toBeHex(1n, 32), desiredProofSize); + + expect(proof.siblingsLength).to.be.eq(0); + expect(proof.siblings).to.be.deep.eq(new Array(desiredProofSize).fill(0)); + expect(proof.existence).to.be.false; + }); + + it("should generate correct proof for the existing nodes", async () => { + const keysCount: number = 50; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keys.length; i++) { + await treaple.addUint(keys[i]); + } + + const treapleRoot: string = await treaple.getUintRoot(); + + for (let i = 0; i < keysCount; i++) { + const randIndex = Math.floor(Math.random() * (Number(await treaple.getUintNodesCount()) - 1)) + 1; + const proof = await treaple.getUintProof(keys[randIndex], 40); + + await verifyCMTProof(proof, treapleRoot, keys[randIndex], true, true); + } + }); + + it("should generate correct proof for the non-existing nodes", async () => { + const keysCount: number = 50; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keys.length; i++) { + await treaple.addUint(keys[i]); + } + + const desiredProofSize = 50; + + await treaple.setDesiredProofSizeUintTreaple(desiredProofSize); + + const treapleRoot: string = await treaple.getUintRoot(); + + for (let i = 0; i < keysCount; i++) { + const randKey = ethers.hexlify(ethers.randomBytes(32)); + const proof = await treaple.getUintProof(randKey, 0); + + expect(proof.siblings.length).to.be.eq(desiredProofSize); + + await verifyCMTProof(proof, treapleRoot, randKey, false, true); + } + }); + + it("should revert if trying to add/remove zero key", async () => { + const reason = "CartesianMerkleTree: the key can't be zero"; + + await expect(treaple.addUint(ZERO_BYTES32)).to.be.rejectedWith(reason); + await expect(treaple.removeUint(ZERO_BYTES32)).to.be.rejectedWith(reason); + }); + + it("should revert if trying to set hasher with non-empty treaple", async () => { + const key = poseidonHash(ethers.toBeHex(2341n)); + + await treaple.addUint(key); + + await expect(treaple.setUintPoseidonHasher()).to.be.rejectedWith("CartesianMerkleTree: treaple is not empty"); + }); + + it("should revert if trying to add a node with the same key", async () => { + const key = poseidonHash(ethers.toBeHex(2341n)); + + await treaple.addUint(key); + + await expect(treaple.addUint(key)).to.be.rejectedWith("CartesianMerkleTree: the key already exists"); + }); + + it("should get empty Node by non-existing key", async () => { + expect((await treaple.getUintNodeByKey(1n)).key).to.be.equal(ZERO_BYTES32); + + await treaple.addUint(ethers.toBeHex(7n, 32)); + + expect((await treaple.getUintNodeByKey(5n)).key).to.be.equal(ZERO_BYTES32); + }); + + it("should get exception if desired size is too low", async () => { + const keysCount: number = 50; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keys.length; i++) { + await treaple.addUint(keys[i]); + } + + await expect(treaple.getUintProof(keys[0], 1)).to.be.rejectedWith( + "CartesianMerkleTree: desired proof size is too low", + ); + }); + }); + + describe("Bytes32 CMT", () => { + beforeEach("setup", async () => { + await treaple.initializeBytes32Treaple(15); + await treaple.setBytes32PoseidonHasher(); + }); + + it("should not initialize twice", async () => { + await expect(treaple.initializeBytes32Treaple(20)).to.be.rejectedWith( + "CartesianMerkleTree: treaple is already initialized", + ); + }); + + it("should correctly set new desired proof size", async () => { + await treaple.setDesiredProofSizeBytes32Treaple(20); + + expect(await treaple.getBytes32DesiredProofSize()).to.equal(20); + }); + + it("should build a Cartesian Merkle Tree correctly with multiple elements", async () => { + for (let i = 1n; i < 20n; i++) { + const key = poseidonHash(ethers.toBeHex(ethers.hexlify(ethers.randomBytes(28)), 32)); + + await treaple.addBytes32(key); + + expect((await treaple.getBytes32NodeByKey(key)).key).to.be.eq(BigInt(key)); + + const proof = await treaple.getBytes32Proof(key, 35); + await verifyCMTProof(proof, await treaple.getBytes32Root(), key, true, true); + } + + expect(await treaple.isBytes32CustomHasherSet()).to.be.true; + }); + + it("should maintain deterministic property", async () => { + const keysCount: number = 100; + const keys: string[] = createRandomArray(keysCount); + + const CartesianMerkleTreeMock = await ethers.getContractFactory("CartesianMerkleTreeMock", { + libraries: { + PoseidonUnit3L: await (await getPoseidon(3)).getAddress(), + }, + }); + + let treapleRoot: string = ""; + + for (let i = 0; i < 5; i++) { + const tmpTreaple = await CartesianMerkleTreeMock.deploy(); + await tmpTreaple.initializeBytes32Treaple(40); + + for (let i = 0; i < keysCount; i++) { + await tmpTreaple.addBytes32(keys[i]); + } + + if (i == 0) { + treapleRoot = await tmpTreaple.getBytes32Root(); + } + + expect(treapleRoot).to.be.eq(await tmpTreaple.getBytes32Root()); + + shuffle(keys); + } + }); + + it("should maintain idempotence", async () => { + const keysCount: number = 30; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keysCount; i++) { + await treaple.addBytes32(keys[i]); + } + + const treapleRoot: string = await treaple.getBytes32Root(); + const usedIndexes: number[] = []; + + for (let i = 0; i < 10; i++) { + let randIndex: number = -1; + + while (true) { + const newRandIndex = + Math.floor(Math.random() * (Number(await treaple.getBytes32NodesCount()) + usedIndexes.length - 1)) + 1; + + if (!usedIndexes.includes(newRandIndex)) { + randIndex = newRandIndex; + usedIndexes.push(newRandIndex); + + break; + } + } + + let currentNode = await treaple.getBytes32Node(randIndex); + + await treaple.removeBytes32(currentNode.key); + + expect(await treaple.getBytes32Root()).to.be.not.eq(treapleRoot); + + await treaple.addBytes32(currentNode.key); + + expect(await treaple.getBytes32Root()).to.be.eq(treapleRoot); + } + }); + + it("should generate correct proof for the existing nodes", async () => { + const keysCount: number = 50; + const keys: string[] = createRandomArray(keysCount); + + for (let i = 0; i < keys.length; i++) { + await treaple.addBytes32(keys[i]); + } + + const treapleRoot: string = await treaple.getBytes32Root(); + + for (let i = 0; i < keysCount; i++) { + const randIndex = Math.floor(Math.random() * (Number(await treaple.getBytes32NodesCount()) - 1)) + 1; + const proof = await treaple.getBytes32Proof(keys[randIndex], 40); + + await verifyCMTProof(proof, treapleRoot, keys[randIndex], true, true); + } + }); + }); + + describe("Address CMT", () => { + beforeEach("setup", async () => { + await treaple.initializeAddressTreaple(15); + await treaple.setAddressPoseidonHasher(); + }); + + it("should not initialize twice", async () => { + await expect(treaple.initializeAddressTreaple(20)).to.be.rejectedWith( + "CartesianMerkleTree: treaple is already initialized", + ); + }); + + it("should correctly set new desired proof size", async () => { + await treaple.setDesiredProofSizeAddressTreaple(20); + + expect(await treaple.getAddressDesiredProofSize()).to.equal(20); + }); + + it("should build a Cartesian Merkle Tree correctly with multiple elements", async () => { + for (let i = 1n; i < 20n; i++) { + const key = ethers.toBeHex(BigInt(await USER1.getAddress()) + i); + + await treaple.addAddress(key); + + expect((await treaple.getAddressNodeByKey(key)).key).to.be.eq(BigInt(key)); + + const proof = await treaple.getAddressProof(key, 35); + await verifyCMTProof(proof, await treaple.getAddressRoot(), key, true, true); + } + + expect(await treaple.isAddressCustomHasherSet()).to.be.true; + }); + + it("should maintain deterministic property", async () => { + const keysCount: number = 100; + const keys: string[] = createRandomArray(keysCount, 20); + + const CartesianMerkleTreeMock = await ethers.getContractFactory("CartesianMerkleTreeMock", { + libraries: { + PoseidonUnit3L: await (await getPoseidon(3)).getAddress(), + }, + }); + + let treapleRoot: string = ""; + + for (let i = 0; i < 5; i++) { + const tmpTreaple = await CartesianMerkleTreeMock.deploy(); + await tmpTreaple.initializeAddressTreaple(40); + + for (let i = 0; i < keysCount; i++) { + await tmpTreaple.addAddress(keys[i]); + } + + if (i == 0) { + treapleRoot = await tmpTreaple.getAddressRoot(); + } + + expect(treapleRoot).to.be.eq(await tmpTreaple.getAddressRoot()); + + shuffle(keys); + } + }); + + it("should maintain idempotence", async () => { + const keysCount: number = 30; + const keys: string[] = createRandomArray(keysCount, 20); + + for (let i = 0; i < keysCount; i++) { + await treaple.addAddress(keys[i]); + } + + const treapleRoot: string = await treaple.getAddressRoot(); + const usedIndexes: number[] = []; + + for (let i = 0; i < 10; i++) { + let randIndex: number = -1; + + while (true) { + const newRandIndex = + Math.floor(Math.random() * (Number(await treaple.getAddressNodesCount()) + usedIndexes.length - 1)) + 1; + + if (!usedIndexes.includes(newRandIndex)) { + randIndex = newRandIndex; + usedIndexes.push(newRandIndex); + + break; + } + } + let currentNode = await treaple.getAddressNode(randIndex); + const currentNodeKey = `0x${currentNode.key.slice(26)}`; + + await treaple.removeAddress(currentNodeKey); + + expect(await treaple.getAddressRoot()).to.be.not.eq(treapleRoot); + + await treaple.addAddress(currentNodeKey); + + expect(await treaple.getAddressRoot()).to.be.eq(treapleRoot); + } + }); + + it("should generate correct proof for the existing nodes", async () => { + const keysCount: number = 50; + const keys: string[] = createRandomArray(keysCount, 20); + + for (let i = 0; i < keys.length; i++) { + await treaple.addAddress(keys[i]); + } + + const treapleRoot: string = await treaple.getAddressRoot(); + + for (let i = 0; i < keysCount; i++) { + const randIndex = Math.floor(Math.random() * (Number(await treaple.getAddressNodesCount()) - 1)) + 1; + const proof = await treaple.getAddressProof(keys[randIndex], 40); + + await verifyCMTProof(proof, treapleRoot, keys[randIndex], true, true); + } + }); + }); +});