Skip to content
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

fix: don't use chainId when calculating domain hash of <=1.2.0 #4616

Merged
merged 2 commits into from
Dec 10, 2024

Conversation

iamacook
Copy link
Member

@iamacook iamacook commented Dec 5, 2024

What it solves

Resolves #4613

How this PR fixes it

For Safe versions <= 1.2.0, the domain separator typehash of the Safe contracts does not include a chainId:

bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;

For versions >= 1.3.0, a chainId is included:

bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;

When calculating the domain hash, we do not take the contract version into account, calculating based on the newer domain separator typehash.

This conditionally includes the chainId when calculating the domain hash for the current Safe, therefore correcting it for <= 1.2.0 versions.

How to test it

Using a Ledger device, observe the domain hash matching that in the interface for all versions from >= 1.0.0.

Checklist

  • I've tested the branch on mobile 📱
  • I've documented how it affects the analytics (if at all) 📊
  • I've written a unit/e2e test for it (if applicable) 🧑‍💻

@iamacook iamacook self-assigned this Dec 5, 2024
Copy link

github-actions bot commented Dec 5, 2024

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review by ChatGPT

},
)
})
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Data Generation Consistency: faker.string.numeric() may generate a numeric string that does not accurately represent a valid Ethereum chain ID. Consider using a predefined valid chain ID for tests to ensure consistency. Example: const chainId = '1'; // Mainnet.

  2. Version Handling: Consider refactoring version strings ('1.0.0', '1.1.1', '1.2.0', '1.3.0', '1.4.1') to constants or enumerations to improve maintainability. This can prevent errors due to typos in version strings and make changes easier if more versions are added later.

  3. Test Coverage: Check if you've covered all relevant versions, including potential edge cases not covered in major or minor versions (e.g., patch versions).

  4. Redundancy in Code: The two it.each blocks are similar except for the domain hash logic. Consider creating a helper function that abstracts out the common code and accepts parameters for differences. This will adhere to the DRY (Don't Repeat Yourself) principle:

    function performDomainHashTest(version, typeHash, includeChainId) {
      const chainId = '1'; // or other valid chain ID
      const safeAddress = faker.finance.ethereumAddress();
    
      const result = getDomainHash({ chainId, safeAddress, safeVersion: version });
    
      const encodedParameters = includeChainId
        ? ['bytes32', 'uint256', 'address']
        : ['bytes32', 'address'];
    
      const expectedHash = keccak256(
        AbiCoder.defaultAbiCoder().encode(
          encodedParameters,
          includeChainId ? [typeHash, chainId, safeAddress] : [typeHash, safeAddress]
        )
      );
    
      expect(result).toEqual(expectedHash);
    }
  5. Magic Strings: The hardcoded type hashes (OLD_DOMAIN_TYPEHASH and NEW_DOMAIN_TYPEHASH) could be accompanied by comments that describe their origin or computations, ensuring comprehension when the code is revisited.

Overall, the approach seems effective for the intended functionality, but consider the above points to enhance code robustness and clarity.

chainId,
verifyingContract: safeAddress,
})
const domainHash = getDomainHash({ chainId, safeAddress, safeVersion })
const messageHash = safeTxData
? TypedDataEncoder.hashStruct('SafeTx', { SafeTx: getEip712TxTypes(safeVersion).SafeTx }, safeTxData)
: undefined
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Inline Function Complexity: The logic for determining whether to include the chainId in the domain hash can be simplified for readability. Consider extracting the version check logic into a separate variable for clarity.

    const includeChainId = semverSatisfies(safeVersion, NEW_DOMAIN_TYPE_HASH_VERSION);
    return TypedDataEncoder.hashDomain({
      ...(includeChainId && { chainId }),
      verifyingContract: safeAddress,
    });
  2. Type Consistency: Ensure all types are declared and used consistently. The type annotations for the getDomainHash parameters are correct but double-check that all related functions and components use consistent types, especially for SafeVersion.

  3. DRY Principle: The logic for creating the domain hash is now effectively extracted into getDomainHash, improving maintainability. However, ensure that this function is reused throughout the codebase wherever the domain hash is constructed to adhere to the DRY principle.

No other significant issues found.

@iamacook iamacook requested a review from usame-algan December 5, 2024 15:20
Copy link

github-actions bot commented Dec 5, 2024

📦 Next.js Bundle Analysis for safe-wallet-web

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 1006.28 KB (🟡 +66 B)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

Copy link

github-actions bot commented Dec 5, 2024

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
73.68% (+0.01% 🔼)
14350/19476
🔴 Branches
51.85% (+0.01% 🔼)
3526/6800
🔴 Functions
57.1% (+0.01% 🔼)
2083/3648
🟡 Lines
75.28% (+0.01% 🔼)
13040/17323

Test suite run success

1667 tests passing in 227 suites.

Report generated by 🧪jest coverage report action from 0fa8cff

safeVersion: SafeVersion
}): string {
return TypedDataEncoder.hashDomain({
...(semverSatisfies(safeVersion, NEW_DOMAIN_TYPE_HASH_VERSION) && { chainId }),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChatGPT has a point, it would be more readable with
const includeChainId = semverSatisfies(safeVersion, NEW_DOMAIN_TYPE_HASH_VERSION)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 0fa8cff.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review by ChatGPT


export function getDomainHash({
chainId,
safeAddress,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No significant issues found.

  • Consider renaming includeChainId to more clearly indicate its purpose, such as isChainIdIncluded, to improve readability.

  • Ensure that semverSatisfies and NEW_DOMAIN_TYPE_HASH_VERSION are properly defined and imported, as they are critical for the logic.

@iamacook iamacook requested a review from katspaugh December 6, 2024 07:41
Copy link

@liliya-soroka
Copy link
Member

Verified

@iamacook iamacook merged commit fb605f5 into dev Dec 10, 2024
16 checks passed
@iamacook iamacook deleted the old-domain-hash branch December 10, 2024 12:50
@github-actions github-actions bot locked and limited conversation to collaborators Dec 10, 2024
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.

Domain Hash Logic in Safe Versions <= 1.2.0
3 participants