feat(#1): add generic TreeNodeLib for EIP-712 tree reconstruction#53
Open
feat(#1): add generic TreeNodeLib for EIP-712 tree reconstruction#53
Conversation
Introduce TreeNodeLib, a generic library for EIP-712 tree node hash reconstruction that eliminates code duplication across PermitNode and NonceNode implementations. Key features: - Parameterized typehash for reusability - Three combination rules: Leaf+Leaf, Node+Node, Node+Leaf - Compact proof structure encoding (O(log n) proof size) - Comprehensive test coverage (1,313 lines of tests) This foundational library enables tree-based cross-chain permits and nonce cancellation with UI transparency and gas efficiency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Oct 31, 2025
There was a problem hiding this comment.
Pull Request Overview
This PR introduces a generic TreeNodeLib library that provides parameterized EIP-712 tree node hash reconstruction, eliminating code duplication between PermitNode and NonceNode implementations. The library includes three combination functions (leaf+leaf, node+node, node+leaf) and a core computeTreeHash function for reconstructing tree hashes from compact proofs.
Key changes:
- Generic tree reconstruction algorithm that works with any EIP-712 typehash
- Compact proof encoding with type flags and position metadata
- Comprehensive test suite covering all combination functions, edge cases, and fuzz tests
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/lib/TreeNodeLib.sol | New generic library with tree reconstruction algorithm and three combination functions |
| test/utils/TreeNodeLibTester.sol | Test helper contract exposing internal library functions for testing |
| test/TreeNodeLib.t.sol | Comprehensive test suite with 65 tests covering all functions, edge cases, and fuzz testing |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Contributor
|
Took me some time to understand but this PR's really cool. Very neat. |
fish-sammy
reviewed
Nov 7, 2025
| ) internal pure returns (bytes32) { | ||
| // Validate proof length does not exceed maximum tree depth | ||
| // Maximum depth is 247 (256 bits - 8 bits for position index - 1 for current element) | ||
| require(proof.length <= 247, "Proof exceeds maximum depth"); |
Comment on lines
135
to
141
| } else { | ||
| if (currentIsNode) { | ||
| currentHash = combineNodeAndLeaf(typehash, currentHash, proof[i]); | ||
| } else { | ||
| currentHash = combineNodeAndLeaf(typehash, proof[i], currentHash); | ||
| } | ||
| } |
Contributor
There was a problem hiding this comment.
Suggested change
| } else { | |
| if (currentIsNode) { | |
| currentHash = combineNodeAndLeaf(typehash, currentHash, proof[i]); | |
| } else { | |
| currentHash = combineNodeAndLeaf(typehash, proof[i], currentHash); | |
| } | |
| } | |
| } else if (currentIsNode && !proofIsNode) { | |
| currentHash = combineNodeAndLeaf(typehash, currentHash, proof[i]); | |
| } else { | |
| // !currentIsNode && proofIsNode | |
| currentHash = combineNodeAndLeaf(typehash, proof[i], currentHash); | |
| } |
| uint256 mask = type(uint256).max << (256 - 8 - proof.length); | ||
| uint256 flagBits = uint256(proofStructure) & ~mask; | ||
| uint256 unusedMask = type(uint256).max >> (8 + proof.length); | ||
| require((flagBits & unusedMask) == 0, "Unused type flags must be zero"); |
Address PR feedback: - Add detailed bit manipulation comments with concrete examples - Improve if/else structure for type-based combinations - Make code more maintainable and easier to understand Changes: - Added comprehensive inline documentation for bit manipulation logic - Refactored nested if/else to explicit else-if chain - Added step-by-step explanations with example values
…me7mv5nn2QUpN6XQ refactor: improve TreeNodeLib code clarity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduce TreeNodeLib, a generic library for EIP-712 tree node hash reconstruction that eliminates code duplication across PermitNode and NonceNode implementations.
This PR provides the foundational infrastructure for tree-based cross-chain permits and nonce cancellation.
Key Features
combineLeafAndLeaf()- Alphabetically sorted leavescombineNodeAndNode()- Alphabetically sorted nodescombineNodeAndLeaf()- Struct order (no sorting)Files Added
src/lib/TreeNodeLib.sol(242 lines) - Generic tree librarytest/TreeNodeLib.t.sol(1,313 lines) - Comprehensive test coverage (71 tests)test/utils/TreeNodeLibTester.sol(73 lines) - Test helperTest Results
Why This PR?
This library will be used by:
By merging this foundation first, subsequent PRs can build on top with minimal conflicts.
Merge Order
Merge this PR first before:
feat/permit-tree(depends on this)feat/nonce-tree(depends on this)🤖 Generated with Claude Code