From 97f018ea2c4ce160535e7ec70e5e01e3a2ee31f1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Nov 2025 22:29:42 +0000 Subject: [PATCH 1/2] refactor: remove unused code and redundant check in NonceManager Address PR feedback: - Remove unused hashNonceNode internal function - Remove redundant emptiness check (handled by hashNoncesToInvalidate) - Remove unused _sortBytes32Array helper function Changes: - Removed hashNonceNode function (only used tests via _hashNonceNode) - Removed redundant empty array check at line 164-166 - Removed orphaned _sortBytes32Array function after hashNonceNode removal - Simplified code by trusting hashNoncesToInvalidate to handle edge cases --- src/NonceManager.sol | 76 -------------------------------------------- 1 file changed, 76 deletions(-) diff --git a/src/NonceManager.sol b/src/NonceManager.sol index 9085119..ef4b487 100644 --- a/src/NonceManager.sol +++ b/src/NonceManager.sol @@ -160,11 +160,6 @@ abstract contract NonceManager is INonceManager, EIP712 { revert WrongChainId(uint64(block.chainid), tree.currentChainInvalidations.chainId); } - // Validate that at least one nonce is being cancelled - if (tree.currentChainInvalidations.salts.length == 0) { - revert EmptyArray(); - } - // Hash the current chain's NoncesToInvalidate as a leaf bytes32 currentChainHash = hashNoncesToInvalidate(tree.currentChainInvalidations); @@ -289,75 +284,4 @@ abstract contract NonceManager is INonceManager, EIP712 { revert InvalidSignature(owner); } } - - /** - * @dev Hash a NonceNode structure for EIP-712 signing - * @dev Recursively hashes the complete tree structure for UI transparency - * @dev Mirrors hashPermitNode implementation for consistency - * @dev Binary tree where leaves are NoncesToInvalidate structs (chain-specific nonce lists) - * @dev Sorts hashes to match TreeNodeLib reconstruction behavior - * @param nonceNode The nonce node tree structure to hash - * @return bytes32 The EIP-712 hash of the complete nonce node structure - */ - function hashNonceNode( - NonceNode memory nonceNode - ) internal pure returns (bytes32) { - bytes32 nodesArrayHash; - bytes32 noncesArrayHash; - - // Hash child nodes in separate block (stack management) - { - bytes32[] memory nodeHashes = new bytes32[](nonceNode.nodes.length); - for (uint256 i = 0; i < nonceNode.nodes.length; i++) { - nodeHashes[i] = hashNonceNode(nonceNode.nodes[i]); - } - // Sort to match TreeNodeLib.combineNodeAndNode behavior - _sortBytes32Array(nodeHashes); - nodesArrayHash = keccak256(abi.encodePacked(nodeHashes)); - } - - // Hash NoncesToInvalidate array in separate block (stack management) - { - bytes32[] memory nonceInvalidationHashes = new bytes32[](nonceNode.nonces.length); - for (uint256 i = 0; i < nonceNode.nonces.length; i++) { - // For single nonce, use the nonce directly (matches hashNoncesToInvalidate logic) - if (nonceNode.nonces[i].salts.length == 1) { - nonceInvalidationHashes[i] = nonceNode.nonces[i].salts[0]; - } else { - // Multiple nonces - hash as NoncesToInvalidate struct (no sorting, preserve order) - nonceInvalidationHashes[i] = keccak256( - abi.encode( - NONCES_TO_INVALIDATE_TYPEHASH, - nonceNode.nonces[i].chainId, - keccak256(abi.encodePacked(nonceNode.nonces[i].salts)) - ) - ); - } - } - // Sort to match TreeNodeLib.combineLeafAndLeaf behavior - _sortBytes32Array(nonceInvalidationHashes); - noncesArrayHash = keccak256(abi.encodePacked(nonceInvalidationHashes)); - } - - return keccak256(abi.encode(NONCE_NODE_TYPEHASH, nodesArrayHash, noncesArrayHash)); - } - - /** - * @dev Helper function to sort bytes32 array in place (bubble sort) - * @param arr Array to sort - */ - function _sortBytes32Array( - bytes32[] memory arr - ) private pure { - uint256 n = arr.length; - for (uint256 i = 0; i < n; i++) { - for (uint256 j = i + 1; j < n; j++) { - if (uint256(arr[i]) > uint256(arr[j])) { - bytes32 temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; - } - } - } - } } From ae16ef1b3ec6ace42ec9c9ac77ef487852c53fb0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Nov 2025 23:50:53 +0000 Subject: [PATCH 2/2] fix: correct indentation in test comment --- test/Permit3Edge.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Permit3Edge.t.sol b/test/Permit3Edge.t.sol index 2638622..9237106 100644 --- a/test/Permit3Edge.t.sol +++ b/test/Permit3Edge.t.sol @@ -734,7 +734,7 @@ contract Permit3EdgeTest is Test { (amount, expiration, ts) = permit3.allowance(owner, address(token), spender); assertEq(amount, 0); // Amount remains unchanged by unlock operation assertEq(expiration, 0); // No expiration (unlocked) - // Note: timestamp should remain from lock operation since unlock only changes expiration + // Note: timestamp should remain from lock operation since unlock only changes expiration assertEq(ts, uint48(block.timestamp)); // Timestamp remains from lock operation }