Skip to content

Conversation

@llbartekll
Copy link
Collaborator

No description provided.

@llbartekll llbartekll marked this pull request as draft November 14, 2025 18:23
@claude
Copy link

claude bot commented Nov 14, 2025

Claude finished @llbartekll's task —— View job


Code Review Complete

Tasks

  • Gather context from changed files
  • Review EIP-712 implementation changes
  • Review descriptor engine and resolver logic
  • Review address book and token data
  • Check test coverage
  • Scan for external domain URLs
  • Finalize review findings

Review Summary

Reviewed PR adding Uniswap Permit2 support, interpolated intents, and address book functionality to clear signing system. Identified several issues requiring attention.


Issues Found

Issue 1: Missing Error Handling in Address Formatting (eip712.rs:391-393)

File: crates/yttrium/src/clear_signing/eip712.rs:391-393

Issue: When hex::decode() fails on malformed address input, the function returns the raw input string which may contain invalid hex characters. This could cause downstream issues or display malformed addresses to users.

let bytes = match hex::decode(cleaned.trim_start_matches("0x")) {
    Ok(bytes) => bytes,
    Err(_) => return address,  // Returns potentially malformed input
};

Recommendation: Return format_raw(value) on decode failure for consistency with other format functions, or add warning when decode fails.


Issue 2: Recursive Merge Without Depth Limit (eip712.rs:224-241, engine.rs)

Files:

  • crates/yttrium/src/clear_signing/eip712.rs:224-241
  • crates/yttrium/src/clear_signing/engine.rs:70-87 (similar pattern in descriptor.rs)

Issue: merge_include() function uses unbounded recursion when merging nested JSON objects. Malicious or deeply nested descriptor JSON could cause stack overflow.

fn merge_include(target: &mut Value, include: Value) {
    if let (Value::Object(target_map), Value::Object(include_map)) = (target, include) {
        for (key, value) in include_map {
            match target_map.get_mut(&key) {
                Some(existing) => {
                    if existing.is_object() && value.is_object() {
                        merge_include(existing, value);  // Unbounded recursion
                    }
                }
                // ...

Recommendation: Add depth limit parameter to prevent stack overflow from deeply nested structures.


Issue 3: External URL in Metadata (uniswap-common-eip712.json:29)

File: crates/yttrium/src/clear_signing/assets/descriptors/uniswap/uniswap-common-eip712.json:29

Issue: Descriptor contains external URL to https://uniswap.org/ which is not an approved company domain (reown.com, walletconnect.com, walletconnect.org).

"info": {
  "legalName": "Uniswap Labs",
  "deploymentDate": "2021-12-14T00:00:00Z",
  "url": "https://uniswap.org/"
}

Recommendation: Verify this external dependency is intentional for protocol integration purposes. Consider documenting trusted third-party protocol URLs.


Issue 4: Nested Address Book Structure Lacks Validation (engine.rs:680-686)

File: crates/yttrium/src/clear_signing/engine.rs:680-686

Issue: merge_address_book_entries() accepts nested object structures but doesn't validate the nesting depth or structure. Deep nesting or large nested objects could impact performance.

serde_json::Value::Object(nested) => {
    for (inner_key, inner_label_value) in nested {
        if let Some(inner_label) = inner_label_value.as_str() {
            map.entry(normalize_address(inner_key))
                .or_insert_with(|| inner_label.to_string());
        }
    }
}

Recommendation: Document expected structure format and consider adding depth/size limits for address book entries.


Issue 5: Silent Failure on Include Processing (resolver.rs:396-434)

File: crates/yttrium/src/clear_signing/resolver.rs:396-434

Issue: extract_includes() only returns error for missing includes but silently continues processing array items that aren't strings. Could hide configuration errors in descriptor JSON.

Value::Array(items) => {
    for item in items {
        let name = item.as_str().ok_or_else(|| {
            ResolverError::DescriptorParse(
                "includes entries must be strings".to_string(),
            )
        })?;
        // ... but no validation of what happens with empty strings or whitespace

Recommendation: Add validation for empty/whitespace-only include names before lookup.


Issue 6: Inconsistent Checksum Address Calculation (engine.rs:736-761)

File: crates/yttrium/src/clear_signing/engine.rs:736-761

Issue: Checksum calculation manually reconstructs string with uppercase chars but doesn't validate the algorithm matches EIP-55 spec for all edge cases (e.g., addresses with no alphabetic chars).

Recommendation: Add test cases covering edge cases: all-numeric addresses, addresses with mixed case input, zero address.


Issue 7: Missing Tests for Interpolated Intents

File: crates/yttrium/tests/clear_signing.rs

Issue: New interpolated_intent field added to DisplayModel but test file doesn't contain tests validating interpolation logic, placeholder substitution, or error handling for malformed templates.

Recommendation: Add tests covering:

  • Valid interpolation with all placeholders present
  • Missing placeholder error
  • Unclosed bracket error
  • Empty placeholder error
  • Nested field paths in interpolation (e.g., {details.amount})

Issue 8: Test Coverage for Permit2 Descriptors

Issue: PR adds Uniswap Permit2 EIP-712 descriptors (eip712-uniswap-permit2.json) with deployments on 14 chains but no integration tests validate the descriptors load correctly or format typed data properly.

Recommendation: Add test case using actual Permit2 typed data to validate descriptor resolution and formatting.


Issue 9: Large Swift File Regeneration

File: platforms/swift/Sources/Yttrium/yttrium.swift

Issue: 2997 line deletion suggests full UniFFI regeneration. While likely auto-generated, should verify regeneration used correct uniffi-bindgen version and that breaking changes aren't introduced to Swift API surface.

Recommendation: Verify Swift platform bindings still compile and existing Swift consumers won't break. Consider noting uniffi version in commit message for traceability.


External Domain URLs

No blocking external domain issues found beyond Issue 3 (Uniswap URL in metadata, which is expected for protocol integration).


Positive Observations

  • Interpolated intent feature properly handles errors with warnings
  • Address book architecture well-documented in spender-address-book.md
  • Descriptor include mechanism enables good code reuse
  • Test coverage includes real-world contract addresses and amounts

@llbartekll llbartekll marked this pull request as ready for review November 17, 2025 21:07
@llbartekll
Copy link
Collaborator Author

@claude review

@claude
Copy link

claude bot commented Dec 1, 2025

Claude finished @llbartekll's task —— View job


🔄 Incremental Review

Tasks

  • Review previous findings and validate current state
  • Check for new issues in latest changes
  • Run automated security checks
  • Finalize review

Validation Summary

Validated previous review findings against current codebase state. All 9 previously identified issues remain present in current code.


Validated Issues (Still Present)

Issue 1: Missing Error Handling in Address Formatting (eip712.rs:367-369)
Status: Confirmed still present

Hex decode failure returns raw input without validation. Could display malformed addresses to users.

let bytes = match hex::decode(cleaned.trim_start_matches("0x")) {
    Ok(bytes) => bytes,
    Err(_) => return address,  // Returns potentially malformed input
};

Issue 2: Recursive Merge Without Depth Limit (resolver.rs:647-664)
Status: Confirmed still present

merge_include_value() uses unbounded recursion. Deeply nested descriptor JSON could cause stack overflow.

fn merge_include_value(target: &mut Value, include: Value) {
    if let (Value::Object(target_map), Value::Object(include_map)) = (target, include) {
        for (key, value) in include_map {
            match target_map.get_mut(&key) {
                Some(existing) => {
                    if existing.is_object() && value.is_object() {
                        merge_include_value(existing, value);  // Unbounded recursion

Recommendation: Add depth limit parameter to prevent stack overflow.


Issue 3: External URL in Metadata (uniswap-common-eip712.json:29)
Status: Confirmed still present

Descriptor contains https://uniswap.org/ which is not an approved domain (reown.com, walletconnect.com, walletconnect.org).

Expected for protocol integration but should be documented as trusted third-party URL.


Issue 4: Nested Address Book Structure Lacks Validation (resolver.rs:519-543)
Status: Confirmed still present

merge_address_book_entries() accepts nested objects without depth/size limits:

serde_json::Value::Object(nested) => {
    for (inner_key, inner_label_value) in nested {
        if let Some(inner_label) = inner_label_value.as_str() {
            map.entry(normalize_address(inner_key))
                .or_insert_with(|| inner_label.to_string());
        }
    }
}

Recommendation: Document expected structure and consider depth/size limits.


Issue 5: Silent Failure on Include Processing (resolver.rs:415-454)
Status: Confirmed still present

extract_includes() doesn't validate empty/whitespace-only include names before lookup. Could hide configuration errors.

Value::Array(items) => {
    for item in items {
        let name = item.as_str().ok_or_else(|| {
            ResolverError::DescriptorParse(
                "includes entries must be strings".to_string(),
            )
        })?;

Recommendation: Add validation for empty/whitespace-only names.


Issue 6: Inconsistent Checksum Address Calculation (engine.rs:617-642)
Status: Confirmed still present

Checksum calculation doesn't validate EIP-55 edge cases (all-numeric addresses, zero address).

Recommendation: Add test cases for edge cases.


Issue 7: Missing Tests for Interpolated Intents
Status: Confirmed still present

Test file has two existing interpolated_intent assertions but no dedicated tests for:

  • Missing placeholder error handling
  • Unclosed bracket error
  • Empty placeholder error
  • Nested field paths (e.g., {details.amount})

Issue 8: Test Coverage for Permit2 Descriptors
Status: Confirmed still present

Test file has one Permit2 test (eip712_uniswap_permit2_formats_allowance) but no tests validating descriptor loading or calldata formatting with actual Permit2 typed data.


Issue 9: Large Swift File Regeneration
Status: Cannot validate (auto-generated)

UniFFI regeneration reduced file from ~3000 lines to ~200 lines. Should verify Swift bindings still compile.


🔒 External Domain URL Detected (Non-blocking)
URL: https://uniswap.org/
File: crates/yttrium/src/clear_signing/assets/descriptors/uniswap/uniswap-common-eip712.json:29

External dependency for protocol integration. Verify intentional.


@llbartekll llbartekll merged commit 86cbb35 into main Dec 2, 2025
11 of 13 checks passed
@llbartekll llbartekll deleted the clear-signing-3 branch December 2, 2025 21:19
@github-actions github-actions bot locked and limited conversation to collaborators Dec 2, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants