-
Notifications
You must be signed in to change notification settings - Fork 3
feat(#1): add generic TreeNodeLib for EIP-712 tree reconstruction #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
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>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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>
|
Took me some time to understand but this PR's really cool. Very neat. |
| ) 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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create error types?
| } else { | ||
| if (currentIsNode) { | ||
| currentHash = combineNodeAndLeaf(typehash, currentHash, proof[i]); | ||
| } else { | ||
| currentHash = combineNodeAndLeaf(typehash, proof[i], currentHash); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } 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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here.
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
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