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

use credential ID to track signers in Account contract #19

Open
wants to merge 54 commits into
base: main
Choose a base branch
from

Conversation

gabspeck
Copy link
Contributor

@gabspeck gabspeck commented Mar 17, 2025

Summary by CodeRabbit

  • New Features

    • Launched an enhanced account deployment process with predictable addresses.
    • Introduced a robust account management system for streamlined key operations.
    • Added a dedicated testing contract enabling simulation of account actions and Ether handling.
    • Added new guidelines for Solidity development and smart contract security.
    • Enhanced documentation for various libraries and contracts.
    • Added a new module for testing functionalities related to accounts.
    • Introduced a comprehensive suite of unit tests for the AccountRegistry contract.
  • Refactor

    • Upgraded account functionality to support additional token interfaces and secure signature verification.
    • Consolidated legacy user management, focusing on account deployment workflows.
  • Chore

    • Upgraded testing framework dependencies and streamlined configuration settings for improved stability.

Copy link

coderabbitai bot commented Mar 17, 2025

Walkthrough

The changes encompass several updates across configuration, smart contracts, and testing modules. A new entry is added to .gitignore, and encoding functions are updated. Several Solidity contracts are refactored: user management in the account factory is removed in favor of a deployAccount flow, and account contracts now include extended key management, enhanced error handling, and token receiver interfaces. New configuration files, documentation improvements, and modules for deployment have been introduced, while legacy contracts and tests have been removed or replaced.

Changes

File(s) Change Summary
.gitignore Added entry .pnpm-store/ to ignore the PNPM store directory.
packages/common/src/encoding/encodeChallenge.ts Updated function signature to include a new credentialId parameter and modified the tuple structure for encoded data.
packages/contracts/.cursorignore, packages/contracts/.cursorrules, packages/contracts/.mocharc.json New configuration files for directory ignoring, Solidity development guidelines, and Mocha testing.
packages/contracts/hardhat.config.ts Removed mining configuration and the environment extension function.
packages/contracts/package.json Upgraded Mocha dependency from ^10.2.0 to ^10.7.3.
packages/contracts/contracts/AbstractAccountFactory.sol Removed user management functions (createUser, getUser) and added a new deployAccount function.
packages/contracts/contracts/Account.sol Expanded to implement IERC721Receiver/IERC1155Receiver, added new error types, enums, structs, and functions for key management and account pause state.
packages/contracts/contracts/AccountFactory.sol Removed the old deployContract function; added deployAccount, computeAccountAddress functions and an AccountDeployed event.
packages/contracts/contracts/AccountRegistry.sol Introduced a new contract for managing user accounts and keys with new structs, events, errors, and functions.
packages/contracts/contracts/Base64.sol Enhanced documentation for Base64 encoding functions and constants.
packages/contracts/contracts/ERC721SafeTransferAccount.sol
packages/contracts/contracts/ERC721SafeTransferAccountFactory.sol
Removed contracts related to ERC721 safe transfer account functionality.
packages/contracts/contracts/P256.sol Improved documentation and added two new signature verification functions.
packages/contracts/contracts/Types.sol Updated the Signature struct to include credentialId and added new structs: Call, SignedCall, and PublicKey.
packages/contracts/contracts/WebAuthn.sol Enhanced documentation and comments explaining the verification logic and constants.
packages/contracts/contracts/test/TestContract.sol Added a new test contract to facilitate testing of account execution and Ether handling.
packages/contracts/ignition/modules/Giano.ts Refactored deployment logic and modified contract registrations; renamed and updated export to include accountRegistry.
packages/contracts/ignition/modules/P256Precompile.ts Added a new module that exports a hexadecimal bytecode string.
packages/contracts/ignition/modules/Testing.ts
packages/contracts/ignition/modules/index.ts
Introduced new modules for deploying test contracts and aggregated deployment modules.
Test Files (under packages/contracts/test/) Removed legacy test suites (Account.ts, AccountFactory.ts, ERC721SafeTransferAccount.ts) and added/updated tests for AccountRegistry, along with new helper functions in testSetup.ts and a new utility function extractEvents in utils.ts.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant AF as AccountFactory
  participant A as Account Contract

  U->>AF: deployAccount(credentialId, publicKey, registry)
  AF->>AF: Compute salt from parameters
  AF->>A: Deploy Account using CREATE2 opcode
  A-->>AF: Return deployed account address
  AF->>U: Return account address and emit AccountDeployed event
Loading
sequenceDiagram
  participant U as User
  participant AR as AccountRegistry
  participant AF as AccountFactory
  participant A as Account Contract

  U->>AR: createUser(keyId, publicKey)
  AR->>AF: Call deployAccount(credentialId, publicKey, registry)
  AF->>A: Deploy new Account contract
  A-->>AF: Return account address
  AR->>AR: Store user & key information, emit UserCreated event
  AR-->>U: Return userId and account address
Loading

Poem

I’m a bunny with a knack for code,
Hopping through changes on a light, bouncy road.
New keys and accounts sprout like spring,
With tests and modules that joyfully sing.
I nibble on bugs and skip each error,
Celebrating each commit with a happy cheer!
Carrots and code—what a marvelous day!

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gabspeck gabspeck changed the base branch from feat/multisig to main March 17, 2025 16:53
@gabspeck gabspeck closed this Mar 17, 2025
@gabspeck gabspeck reopened this Mar 17, 2025
@gabspeck gabspeck closed this Mar 17, 2025
@gabspeck gabspeck reopened this Mar 17, 2025
@gabspeck
Copy link
Contributor Author

@coderabbitai full review

Copy link

coderabbitai bot commented Mar 17, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
packages/contracts/ignition/modules/P256Precompile.ts (1)

2-2: ⚠️ Potential issue

Remove stray numeral at the end of the file.
The extra line containing just the numeral "2" appears to be an accidental artifact. This could lead to a syntax error in TypeScript since it is interpreted as an extraneous statement following the export. Please remove this line to ensure the file contains only the intended export.

🧹 Nitpick comments (21)
packages/contracts/ignition/modules/Testing.ts (1)

1-7: Consider adding documentation for the Testing module

The module structure follows Hardhat Ignition patterns correctly, but lacks documentation explaining its purpose and how it relates to the credential ID tracking feature mentioned in the PR title.

 import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';
 
+/**
+ * Testing module for deploying test contracts
+ * Used for testing account functionality including credential ID tracking
+ */
 export default buildModule('Testing', (m) => {
   const testContract = m.contract('TestContract');
 
   return { testContract };
 });
packages/contracts/.cursorrules (1)

21-21: Consider allowing minimal inline code comments for clarity.

Line 21's restriction on adding comments (beyond NatSpec) could hamper maintainability when dealing with complex logic. A minimal approach aligning with readability is recommended.

packages/contracts/contracts/P256.sol (1)

31-33: Use require(success, "Precompile call failed") for clarity.

While the call to the precompile is expected to succeed, require is often safer than assert to give a clear error message if unexpected failures occur.

packages/contracts/ignition/modules/Giano.ts (1)

8-13: Consider awaiting the precompile deployment.

Using void to ignore the Promise might lead to race conditions if subsequent operations depend on the precompile being deployed first. Consider making this an awaited call or ensuring proper sequencing.

packages/contracts/contracts/WebAuthn.sol (2)

53-59: Clarify partial spec coverage
The doc block for checkAuthFlags is thorough. For completeness, consider reiterating in the doc that some other WebAuthn checks (e.g., attestation validations) lie outside this function’s scope.


91-115: Verbose signing verification documentation
The expanded comments for verifySignature clearly indicate which portions of the WebAuthn flow are covered. You might wish to add a brief reminder that certain aspects (e.g., attestation or advanced hashing checks) are not performed.

packages/contracts/contracts/AbstractAccountFactory.sol (1)

14-22: Added function doc
Great explanations for the parameters and return value in deployAccount. Consider specifying whether or not the caller must have special permissions to invoke this function (access control).

packages/contracts/test/utils.ts (2)

49-57: Avoid suppressing TypeScript checks
//@ts-ignore might hide potential typing issues and hamper future maintainability. Consider defining the proper interface or type for these properties to prevent ignoring checks.

-    //@ts-ignore
     clientDataJSON: clientDataJSON,
-    //@ts-ignore
     authenticatorData: authenticatorData,
-    //@ts-ignore
     signature: signature,

59-82: New event extraction utility
This function effectively parses logs for a specified event. However, you may want to filter by the contract’s address to avoid parsing logs from other contracts in the receipt, which can lead to unexpected outcomes.

+ // Optionally, filter by log.address == contract.address before parsing
packages/contracts/test/AccountRegistry.test.ts (3)

9-13: Add negative test for an uninitialized factory.
Currently, the test verifies that the AccountRegistry initializes with the correct factory address but does not verify behavior when the factory is absent or incorrectly deployed. Consider adding a test to ensure the contract reverts or behaves as expected if the factory address is invalid.


17-38: Enhance test coverage by checking for non-zero userID.
You're already validating that the account is non-zero. As an additional safeguard, you could confirm that the emitted userId is non-zero to reinforce that user creation is properly registered.


79-99: Check for credentialId in UserCreated event assertions.
This test verifies public key fields but does not assert that the credentialId matches what's passed to createUser. Including a check for the credentialId in the UserCreated event would further strengthen the test accuracy.

packages/contracts/contracts/AccountFactory.sol (1)

31-41: Consider restricting public access or clarifying its intent.
The deployAccount function is marked public, allowing anyone to deploy accounts. This might be intentional if you want it to be fully permissionless. If not, consider adding an access control modifier or clarifying in documentation that this is by design.

packages/contracts/test/helpers/testSetup.ts (1)

39-67: Consider adding error handling around deployment.
The deployContracts function wraps calls to hre.ignition.deploy(ignitionModules) without catching potential failures. While failures may be rare in local testing, adding a try/catch or expanded error reporting can make it easier to debug if deployment fails unexpectedly.

packages/contracts/contracts/test/TestContract.sol (3)

25-28: Consider adding access control for setValue.

Currently, any address can call setValue, which might not be an issue for a testing scenario. However, if you plan to reuse this contract in more controlled environments, consider restricting who can update value.


52-57: Reentrancy consideration in withdraw.

Using call{value: _amount}("") can introduce reentrancy vectors if internal state updates or additional logic are added later. Although this is primarily a test contract, it’s safer to consider using a nonReentrant mechanism (e.g., OpenZeppelin’s ReentrancyGuard) or the checks-effects-interactions pattern.


92-97: Use caution when relying on receive().

The receive() fallback to emit EtherReceived is a convenient way to capture Ether transfers. Just ensure that the contract does not perform any heavyweight logic here, to guard against issues if the contract is used in scenarios with multiple or frequent ETH sends.

packages/contracts/contracts/AccountRegistry.sol (2)

125-131: Non-sequential ID generation logic.

Using block.timestamp, block.prevrandao, address(this), and msg.sender is a practical approach for uniqueness under typical conditions. However, these on-chain values don't guarantee strong randomness properties. If strict uniqueness or randomness is mission-critical, consider additional off-chain or VRF-based randomness.


278-299: Key removal consistency in notifyKeyRemoved.

Unlinking the key from keyToAccount ensures that the system remains consistent. Just confirm that child contracts or external references don’t rely on the old key mapping after removal. The usage of the event KeyUnlinked also helps external systems track updates.

packages/contracts/contracts/Account.sol (1)

495-517: Potential partial cleanup in removeKey.

After removeKey sets the key’s role to Role.NONE, the KeyInfo struct remains in the keys mapping. If you want to free up storage or ensure no residual data (publicKey, etc.) remains, consider deleting keys[credentialId] entirely once you no longer need that data.

- keys[credentialId].role = Role.NONE;
+ delete keys[credentialId];
packages/contracts/ignition/modules/P256Precompile.ts (1)

1-1: Add file-level documentation for clarity.
Consider adding a brief comment at the top of the file describing the purpose of this exported hexadecimal string. For example, explain that the string represents the precompiled bytecode for the P256 precompile used in the Account contract deployment process. This will improve maintainability and ease the onboarding of future contributors.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7867f1 and f4c0e7d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (29)
  • .gitignore (1 hunks)
  • packages/common/src/encoding/encodeChallenge.ts (1 hunks)
  • packages/contracts/.cursorignore (1 hunks)
  • packages/contracts/.cursorrules (1 hunks)
  • packages/contracts/.mocharc.json (1 hunks)
  • packages/contracts/contracts/AbstractAccountFactory.sol (1 hunks)
  • packages/contracts/contracts/Account.sol (2 hunks)
  • packages/contracts/contracts/AccountFactory.sol (1 hunks)
  • packages/contracts/contracts/AccountRegistry.sol (1 hunks)
  • packages/contracts/contracts/Base64.sol (1 hunks)
  • packages/contracts/contracts/ERC721SafeTransferAccount.sol (0 hunks)
  • packages/contracts/contracts/ERC721SafeTransferAccountFactory.sol (0 hunks)
  • packages/contracts/contracts/P256.sol (2 hunks)
  • packages/contracts/contracts/Types.sol (1 hunks)
  • packages/contracts/contracts/WebAuthn.sol (3 hunks)
  • packages/contracts/contracts/test/TestContract.sol (1 hunks)
  • packages/contracts/hardhat.config.ts (0 hunks)
  • packages/contracts/ignition/modules/ERC721SafeTransferAccount.ts (0 hunks)
  • packages/contracts/ignition/modules/Giano.ts (1 hunks)
  • packages/contracts/ignition/modules/P256Precompile.ts (1 hunks)
  • packages/contracts/ignition/modules/Testing.ts (1 hunks)
  • packages/contracts/ignition/modules/index.ts (1 hunks)
  • packages/contracts/package.json (1 hunks)
  • packages/contracts/test/Account.ts (0 hunks)
  • packages/contracts/test/AccountFactory.ts (0 hunks)
  • packages/contracts/test/AccountRegistry.test.ts (1 hunks)
  • packages/contracts/test/ERC721SafeTransferAccount.ts (0 hunks)
  • packages/contracts/test/helpers/testSetup.ts (1 hunks)
  • packages/contracts/test/utils.ts (3 hunks)
💤 Files with no reviewable changes (7)
  • packages/contracts/hardhat.config.ts
  • packages/contracts/contracts/ERC721SafeTransferAccountFactory.sol
  • packages/contracts/test/ERC721SafeTransferAccount.ts
  • packages/contracts/test/AccountFactory.ts
  • packages/contracts/ignition/modules/ERC721SafeTransferAccount.ts
  • packages/contracts/test/Account.ts
  • packages/contracts/contracts/ERC721SafeTransferAccount.sol
🔇 Additional comments (37)
.gitignore (1)

5-5: Appropriate .pnpm-store Ignored Entry

The addition of .pnpm-store/ is a good practice when using pnpm, ensuring that cached dependency data isn’t tracked in version control. This helps maintain a clean repository.

packages/contracts/.cursorignore (1)

1-4: Appropriate directory exclusions added

These directories contain generated files, dependencies, and cache data that should be excluded from the cursor tool's processing. This improves editor performance and prevents unnecessary processing of non-source files.

packages/contracts/.mocharc.json (1)

1-7: Well-configured Mocha test settings

This configuration properly sets up Hardhat integration with Mocha and includes a reasonable timeout value (40s) for blockchain tests that may involve complex transactions. The test pattern correctly targets TypeScript tests.

packages/contracts/package.json (1)

42-42: Good practice keeping Mocha updated

Updating from 10.2.0 to 10.7.3 brings in bug fixes and improvements to the testing framework. This is a positive maintenance change that supports the new Mocha configuration file.

packages/contracts/ignition/modules/index.ts (1)

1-10: Clean modular structure for contract deployment

This new file creates a modular structure to organize Hardhat Ignition deployment configurations. It effectively combines the Giano and Testing modules into a single export, making it easier to manage deployment configurations across different environments.

The pattern follows best practices by:

  1. Using the Hardhat Ignition buildModule function
  2. Properly importing and composing sub-modules
  3. Using object spread to merge module exports cleanly
packages/common/src/encoding/encodeChallenge.ts (4)

3-3: Appropriate import for new parameter type

The addition of BytesLike import from ethers is necessary to support the new credential ID parameter.


6-6: Function signature updated to include credential ID

The function signature has been updated to accept a credential ID parameter, which aligns with the PR objective of tracking signers by their credential IDs.


13-15: Updated tuple encoding structure to include credential ID

The ABI encoding structure has been appropriately modified to include the credential ID as part of the tuple type.


17-18: Added credential ID to encoded data

The credential ID is now included as the first element in the encoded data array, ensuring it's captured in the WebAuthn signature challenge.

packages/contracts/contracts/Types.sol (6)

4-9: Improved documentation for Types library

The enhanced documentation clearly explains the purpose and usage of the Types library, which improves code readability and maintainability.


11-20: Well-documented Signature struct

The detailed documentation for each field in the Signature struct makes it clear what each parameter represents and how it's used in WebAuthn signatures.


22-22: New credential ID field added to Signature struct

The addition of the credentialId field to the Signature struct is consistent with the changes in encodeChallenge.ts and supports the PR's objective of tracking signers by their credential IDs.


31-41: Well-structured Call struct for contract interactions

The new Call struct is properly documented and provides a clean way to represent external contract calls with target address, value, and calldata.


43-51: SignedCall struct for authorized transactions

The SignedCall struct combines call parameters with the signature in a well-organized structure, facilitating authenticated contract interactions.


53-61: PublicKey struct for ECDSA P-256 keys

The PublicKey struct is well-defined for representing ECDSA P-256 public keys with proper documentation of the x and y coordinates.

packages/contracts/contracts/Base64.sol (5)

8-13: Enhanced library documentation

The improved documentation includes title, author, and a clearer description of the library's purpose with reference to RFC 4648, making it more professional and informative.


16-16: Clarified table comment

Changed from singular to plural to correctly indicate multiple encoding/decoding tables.


23-26: Better function documentation for encode method

The enhanced documentation clearly explains that this method produces standard Base64 encoding with padding.


33-36: Better function documentation for encodeURL method

The enhanced documentation clearly explains that this method produces URL-safe Base64 encoding without padding.


43-48: Improved internal function documentation

The documentation for the internal _encode function now clearly explains its dual purpose for both standard and URL-safe encoding, as well as its optimization using assembly.

packages/contracts/.cursorrules (1)

4-22: Comprehensive guidelines documented.

These lines set forth a clear set of coding principles and best practices. No functional code concerns; everything neatly organized.

packages/contracts/contracts/P256.sol (1)

5-9: Excellent documentation updates.

These doc additions provide clarity on the intended usage, parameters, and behavior of the signature verification functions.

Also applies to: 14-23, 42-51

packages/contracts/ignition/modules/Giano.ts (2)

3-3: Import statement looks good.

The dedicated module for the precompile is a clean, modular approach.


15-17: Smooth integration of account contracts.

Registering AccountRegistry with the accountFactory constructor parameter is consistent and maintains clarity in your deployment module.

packages/contracts/contracts/WebAuthn.sol (3)

8-13: Enhanced high-level library documentation
These doc updates thoroughly explain the library’s purpose and reference the WebAuthn specification. This context helps developers better understand the scope and usage of this library.


15-22: Improved function doc block
The added explanations for parameters and return values in contains provide clarity on its purpose and expected usage.


47-51: Constants documentation
Detailing the authenticator-data flag bits makes the code self-explanatory and reduces confusion regarding the WebAuthn bitmask definitions.

packages/contracts/contracts/AbstractAccountFactory.sol (1)

6-12: Comprehensive contract-level doc improvements
The high-level comments describing this abstract contract enhance visibility into its intended usage and architecture.

packages/contracts/test/utils.ts (1)

18-22: Add type definition for WebAuthn response
Documenting the new WebAuthn response format clarifies the structure of returned data.

packages/contracts/contracts/test/TestContract.sol (1)

72-82: Multi-operation approach is well-structured.

The multiOperation function cleanly aggregates multiple actions (value update, message update, Ether deposit) in a single transaction. Maintaining clear event emissions for each action within the function is a good practice for transparency in testing.

packages/contracts/contracts/AccountRegistry.sol (2)

245-271: Key addition requests handled well.

The requestAddKey function appropriately checks for a non-zero user ID and whether the key is already linked. Emitting a KeyRequestCreated event also improves on-chain traceability. This is consistent with the principle of single-responsibility for user and key management.


205-234:

✅ Verification successful

Race condition concern in createUser.

Although highly unlikely, there is a theoretical race where two concurrent transactions generate the same userId. You already mitigate this by reverting if users[userId].account is nonzero. Just be aware of this edge case.

Would you like to confirm by scanning the transaction flow or relevant logs to detect any repeated userId collisions in subsequent deployments?


🏁 Script executed:

#!/bin/bash
# Searching logs for repeated userId usage in deployment or creation
rg "UserAlreadyExists"

Length of output: 207


User Collision Race Condition: No Incidents Detected

Based on the log scan, there is no evidence of repeated UserAlreadyExists collisions in practice. The revert mechanism when encountering a duplicate userId is functioning as intended, mitigating the theoretical race condition. Please continue monitoring, but no further action is needed at this time.

packages/contracts/contracts/Account.sol (5)

26-33: Clear error-handling patterns.

Defining explicit errors (e.g., InvalidSignature, NotAuthorized) provides a well-structured approach to revert conditions. This is a best practice for readability and troubleshooting.


205-209: Events for key updates enhance auditability.

Emitting events like KeyAdded, KeyRemoved, and KeyRoleChanged facilitates transparent on-chain monitoring. This design choice simplifies external auditing and off-chain indexing of key state changes.


445-467: approveKeyRequest flow is well-defined.

The function carefully checks:

  • Admin operation type
  • Request existence
  • Key uniqueness
  • Registry notification (notifyKeyAdded)

These checks align with a secure multi-step key generation flow. Ensure downstream references to the new key are consistent.


584-596: Verification of execute flow is robust.

The execute function includes:

  • validSignature check
  • nonReentrant guard
  • whenNotPaused check
  • Rethrowing of revert reason

This is a thorough approach to secure transaction execution.


751-768:

❓ Verification inconclusive

pauseAccount/unpauseAccount usage.

Pausing logic is straightforward. The indefinite pause feature (_until == 0 ? type(uint256).max : _until;) is useful for emergency scenarios. Just note that this contract design grants full pause capability to any admin key. Ensure that the risk of losing all keys or having a malicious admin is addressed operationally.

Would you like to confirm that each admin key is properly secured off-chain to mitigate accidental or malicious indefinite pauses?


🏁 Script executed:

#!/bin/bash
# Potential approach to see if there's a documented emergency policy for admin keys
rg "admin key" -A 8

Length of output: 17769


Action Required: Confirm Robust Off-Chain Security for Admin Keys

The implementation for pauseAccount and unpauseAccount is clear and functions as intended—setting the pause indefinitely by assigning type(uint256).max when _until is 0, which is valuable for emergency interventions. However, our review indicates that admin keys, which grant full pause capability, are only referenced within the test suites without explicit documentation of off-chain security measures or emergency policies. Please confirm that there is an established, robust operational procedure to secure admin keys to prevent accidental or malicious indefinite pauses.

  • Verify that off-chain key management practices and emergency policies for admin keys are clearly documented.
  • Consider adding inline notes or reference documentation in the codebase to highlight these operational safeguards.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
packages/contracts/contracts/Types.sol (1)

11-20: Consider off-chain storage of large WebAuthn data.
Storing extensive data such as clientDataJSON on-chain can be expensive in terms of gas and storage. Consider storing large or unstructured data (e.g., JSON) off-chain or using a more compact data structure if feasible.

packages/contracts/contracts/AbstractAccountFactory.sol (1)

14-22: Abstract deploy function is well-defined.
The parameters and return value are clearly specified. Consider whether you want to restrict access to specific roles or addresses.

packages/contracts/contracts/Account.sol (2)

7-8: Confirm intent to handle token transfers
By importing and implementing both IERC721Receiver and IERC1155Receiver, this contract can receive ERC721 and ERC1155 tokens. While this broadens functionality, it also can introduce reentrancy concerns and complexity in scenarios where token transfers trigger external calls. Verify that this expanded scope is intentional and that use of ReentrancyGuard (or equivalent measures) covers all relevant paths.


417-437: Block timestamp usage for request ID
Line 430 uses block.timestamp to generate requestId, which risks collisions when multiple requests occur in the same block from the same sender. Consider including a counter or combining additional entropy to mitigate this edge case.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4c0e7d and 5ffe473.

📒 Files selected for processing (6)
  • packages/contracts/contracts/AbstractAccountFactory.sol (1 hunks)
  • packages/contracts/contracts/Account.sol (2 hunks)
  • packages/contracts/contracts/AccountFactory.sol (1 hunks)
  • packages/contracts/contracts/AccountRegistry.sol (1 hunks)
  • packages/contracts/contracts/Types.sol (1 hunks)
  • packages/contracts/test/AccountRegistry.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/contracts/test/AccountRegistry.test.ts
🔇 Additional comments (21)
packages/contracts/contracts/Types.sol (4)

4-9: Documentation well-written and comprehensive.
These lines provide clear, structured documentation for the library, promoting ease of usage and maintainability.


31-41: Clear struct definitions for call parameters.
Using a dedicated Call struct to encapsulate call information is clean and intuitive. It promotes reusability and clarifies the code’s intent.


43-51: Signed call design is consistent and straightforward.
Encapsulating signed calls in a dedicated struct is a good pattern, simplifying verification logic elsewhere in the code.


53-61: Public key struct is well-defined.
Storing x and y coordinates for an ECDSA P-256 key clarifies the curve parameters, though consider referencing or validating the curve explicitly if needed.

packages/contracts/contracts/AbstractAccountFactory.sol (1)

6-12: Robust documentation for the abstract factory.
Providing clear descriptions of purpose and design expectations fosters consistent implementations in derived contracts.

packages/contracts/contracts/AccountFactory.sol (4)

8-14: Documentation aligns with factory pattern.
These lines accurately describe the factory contract’s purpose and usage.


16-22: Event emission improves auditability.
Emitting AccountDeployed helps external services and users track deployments. Good use of indexed parameters.


23-41: Deterministic deployment via CREATE2 is correctly implemented.
Using keccak256 of the parameters as the salt is a robust approach to produce predictable addresses. Ensure collisions won’t occur from identical inputs in different contexts.


43-62: Predictable address computation function is added value.
Allowing clients to compute the address before deployment is useful. Implementation follows the standard CREATE2 formula.

packages/contracts/contracts/AccountRegistry.sol (7)

8-16: Comprehensive contract documentation.
The high-level overview and usage notes provide context and prevent misuse, which benefits external integrators.


17-29: User struct naming is consistent and descriptive.
Storing credentialId, publicKey, and account together clarifies ownership. The approach fits well with your account-based model.


31-41: Mappings are well-organized for user-credential-account relationships.
Each mapping clearly represents a specific relationship, reducing confusion.


73-80: Event AddCredentialRequestCreated fosters transparency.
Emitting this event helps external clients track credential assignment states.


197-234: New user creation flow is logically sound.
The steps for generating a user ID, deploying the account, and linking a credential are transparent. Checking for duplicate credentials ensures uniqueness.


245-271: Credential addition request flow is well-structured.
The registry enforces a single credential-to-account mapping before delegating the actual addition to the Account contract. This pattern is secure and modular.


278-299: Credential linking/unlinking notifications are consistent.
The notifyKeyAdded and notifyCredentialRemoved callbacks keep the registry up to date. Reverts on mismatched credential ownership protect against misuse.

packages/contracts/contracts/Account.sol (5)

92-96: Clear and contextual pause error
Defining a specific AccountIsPaused error with a timestamp parameter helps convey precise pausing conditions to callers.


87-90: Protecting against removal of the final admin key
The LastAdminCredential error prevents losing the final administrative credential. This is an important safeguard to maintain continuous governance control.


445-467: Good adherence to checks-effects-interactions pattern
In approveKeyRequest, storage is updated and the credential request is removed before calling notifyKeyAdded. This sequence reduces reentrancy risks and ensures consistent storage in case of external call failures.


745-758:

✅ Verification successful

Indefinite pause mechanism
Using type(uint256).max for _until = 0 effectively locks the contract indefinitely. Verify that at least one active admin key remains accessible to call unpauseAccount, preventing a scenario of permanent deadlock.


🏁 Script executed:

#!/bin/bash
# Checking presence of unpause references in the code and ensuring admin can still call it
rg "unpauseAccount" -A 5

Length of output: 2342


Indefinite Pause Safety Validation

The use of type(uint256).max for _until == 0 to represent an indefinite pause is intentional. Our verification confirms that the unpauseAccount function is implemented in packages/contracts/contracts/Account.sol and is exercised by tests in packages/contracts/test/Account.test.ts, ensuring that an admin can always unpause the account. Please continue to ensure that admin key management is robust so that at least one valid admin key remains active to avoid any potential deadlock in production.


98-106:

❓ Verification inconclusive

Ensure role checks align with intended privileges
Enumeration of roles (NONE, EXECUTOR, ADMIN) is straightforward, and higher levels inherit lower-level permissions. However, confirm at runtime that execute and executeBatch robustly enforce a minimum of EXECUTOR privileges rather than just checking for non-NONE.

Use the following script to confirm references to _hasRole in the code:


🏁 Script executed:

#!/bin/bash
rg "_hasRole" -A 5

Length of output: 937


Action Required: Verify Role Enforcement in Execution Functions
The _hasRole implementation appears to correctly compare roles using their underlying uint8 values. We see a check enforcing an admin-level requirement (e.g., if (!_hasRole(sig.credentialId, Role.ADMIN))) that properly validates that the credential meets or exceeds the required role. However, as noted in the original comment, please ensure that the execute and executeBatch functions (or any other execution-related methods) are not merely checking for non-NONE but explicitly enforce a minimum of EXECUTOR privileges by calling _hasRole with Role.EXECUTOR.

  • Confirm that both execute and executeBatch invoke _hasRole with a minimum requirement of Role.EXECUTOR.
  • Verify that no execution pathway inadvertently allows roles below EXECUTOR by only checking against NONE.

Comment on lines 603 to 621
function executeBatch(
BatchCall calldata batch
) external payable validSignature(bytes.concat(getBatchChallenge(batch.calls)), batch.signature) nonReentrant whenNotPaused {
uint256 callsLength = batch.calls.length;
require(callsLength > 0, 'No calls to execute');

for (uint256 i = 0; i < callsLength; i++) {
Types.Call calldata currentCall = batch.calls[i];
(bool success, bytes memory result) = currentCall.target.call{value: currentCall.value}(currentCall.data);
if (!success) {
assembly {
revert(add(result, 32), mload(result))
}
}
}

emit Executed(currentNonce, address(0), 0, abi.encode(batch.calls));
currentNonce++;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Atomic batch execution
executeBatch reverts on the first failing call, causing the entire batch to revert. While this ensures atomicity, it may be overly restrictive if partial successes are acceptable in some workflows.

Consider adding a variant function that can handle individual call failures more gracefully if needed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
packages/contracts/test/Account.test.ts (1)

2120-2123: TODO: Implement reentrancy test.
The stub at line 2121 indicates an intention to verify reentrancy protection, but it’s currently unimplemented. Completing this test will help ensure robust security coverage.

Would you like me to propose a reentrancy scenario for thorough testing?

packages/contracts/contracts/AccountRegistry.sol (1)

125-127: Note on randomness.
Using block.prevrandao as part of the salt generation can be manipulated by block producers and is not cryptographically secure. If true randomness or strong uniqueness is critical, consider using a more secure source.

Would you like me to propose an alternative approach or integrate an oracle-based VRF?

packages/contracts/contracts/Account.sol (2)

557-574: Consider storing the revert reason in a more explicit event.

Reverting via inline assembly is a typical way to propagate the target contract’s revert reason. For verbose debugging and better off-chain tracing, consider emitting an additional event or logging the revert reason in a more structured format.


608-613: Optional stricter requirement for admin usage.

By default, _validateAdminSignature allows admin signatures without requiring user verification in WebAuthn. If desired, toggling requireUserVerification to true could further strengthen the admin signature checks, though this depends on your project’s security policies.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ffe473 and bee5822.

📒 Files selected for processing (4)
  • packages/contracts/contracts/Account.sol (2 hunks)
  • packages/contracts/contracts/AccountRegistry.sol (1 hunks)
  • packages/contracts/test/Account.test.ts (1 hunks)
  • packages/contracts/test/AccountRegistry.test.ts (1 hunks)
🔇 Additional comments (9)
packages/contracts/test/AccountRegistry.test.ts (2)

1-360: Thorough test coverage.
This test suite thoroughly covers user creation, credential management, account lookup, and credential request flows, including event emission and revert conditions. The structure is well organized and consistent with Hardhat best practices.


102-115: Naming mismatch “CredentialAlreadyUnlinked”.
These tests expect the CredentialAlreadyUnlinked error even though the docstrings in your contract indicate the credential is already linked. This was flagged in a past review. Consider renaming the error to CredentialAlreadyLinked to avoid confusion.

packages/contracts/test/Account.test.ts (1)

1-2124: Impressive test coverage.
This test suite methodically validates critical functionalities (credential requests, role changes, transaction execution, pausing, etc.). It’s well structured with meaningful test names that provide comprehensive coverage.

packages/contracts/contracts/AccountRegistry.sol (1)

98-98: Naming discrepancy in CredentialAlreadyUnlinked error.
The docstring states it is thrown “when a credential is already linked,” but the error name suggests the opposite. This was previously flagged and still remains. Rename to CredentialAlreadyLinked for better clarity.

packages/contracts/contracts/Account.sol (5)

7-8: Great addition for NFT compatibility.

By importing and implementing the ERC721 and ERC1155 receiver interfaces, the contract can safely accept NFT transfers. This change is aligned with common multi-token wallet practices.


18-18: Interface expansion is well-structured.

Declaring the contract to implement IERC1271, IERC721Receiver, and IERC1155Receiver in addition to ReentrancyGuard cleanly consolidates multi-token and signature-verification functionality into a single contract.


66-70: Restrict credential creation to registry.

The OnlyRegistryCanAddCredentials error and its usage in modifier onlyRegistry() effectively prevents unauthorized credential management from external callers. This is a solid security measure.


223-228: Separate admin and transaction nonces is a good pattern.

Storing adminNonce and currentNonce distinctly prevents replay attacks on both admin actions and normal calls, enhancing security. The explicit adminKeyCount also makes it straightforward to enforce the “last admin” guard.


576-599: Atomic batch mode can be restrictive.

This contract reverts on the first failing call in a batch, ensuring atomicity. However, if partial executions are acceptable for your use case, consider providing an alternate function that continues executing and surfaces individual failures.

Comment on lines +241 to +247
constructor(Types.PublicKey memory _initialAdminKey, bytes memory _initialCredentialId, address _registry) {
credentials[_initialCredentialId] = CredentialInfo({publicKey: _initialAdminKey, role: Role.ADMIN, credentialId: _initialCredentialId, pending: false});
registry = _registry;
adminKeyCount = 1;

emit CredentialAdded(_initialAdminKey, Role.ADMIN);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Validate initial parameters.

While the constructor properly sets an initial admin credential, consider adding checks to ensure _registry is not the zero address and the initial credential/key are non-trivial. This avoids accidental deployment misconfiguration.

 constructor(Types.PublicKey memory _initialAdminKey, bytes memory _initialCredentialId, address _registry) {
+    require(_registry != address(0), "Registry address cannot be zero");
+    // Optionally check that _initialAdminKey is not empty
     credentials[_initialCredentialId] = CredentialInfo({
       ...
     });
     registry = _registry;
     ...
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constructor(Types.PublicKey memory _initialAdminKey, bytes memory _initialCredentialId, address _registry) {
credentials[_initialCredentialId] = CredentialInfo({publicKey: _initialAdminKey, role: Role.ADMIN, credentialId: _initialCredentialId, pending: false});
registry = _registry;
adminKeyCount = 1;
emit CredentialAdded(_initialAdminKey, Role.ADMIN);
}
constructor(Types.PublicKey memory _initialAdminKey, bytes memory _initialCredentialId, address _registry) {
require(_registry != address(0), "Registry address cannot be zero");
// Optionally check that _initialAdminKey is not empty
credentials[_initialCredentialId] = CredentialInfo({
publicKey: _initialAdminKey,
role: Role.ADMIN,
credentialId: _initialCredentialId,
pending: false
});
registry = _registry;
adminKeyCount = 1;
emit CredentialAdded(_initialAdminKey, Role.ADMIN);
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/contracts/test/Account.test.ts (2)

2137-2139: Implement or remove the placeholder reentrancy test.

The "should prevent reentrancy attacks" test is not implemented. Consider either implementing reentrancy scenarios to validate that Account is protected, or removing the placeholder if no reentrancy vectors exist.


1146-1147: Use deterministic block timestamps instead of real-time values.

Relying on Math.floor(Date.now() / 1000) can produce non-deterministic test behavior if the system clock and Hardhat test environment diverge. Consider using hardhat_setNextBlockTimestamp or a fixture-based time progression approach for stable test outcomes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bee5822 and 3d576ab.

📒 Files selected for processing (2)
  • packages/contracts/contracts/Account.sol (2 hunks)
  • packages/contracts/test/Account.test.ts (1 hunks)
🔇 Additional comments (10)
packages/contracts/test/Account.test.ts (4)

1683-1724: Validate indefinite pause behavior.

Setting _until to 0 triggers an indefinite pause by assigning type(uint256).max. Ensure this aligns with your business logic, especially if indefinite pauses might lock out legitimate users permanently.


1009-1029: Single transaction execution looks correct.

The test validates successful calls, revert correctness, and result verification. No issues are found for these lines.


1050-1071: Nonce incrementation test is robust.

The test properly checks that the nonce updates only after a successful transaction. This ensures replay protection.


1345-1374: Batch calls revert atomically.

The test confirms an all-or-nothing approach for batch calls, enhancing atomicity. This is correct if partial successes are unwelcome.

packages/contracts/contracts/Account.sol (6)

241-247: Validate constructor parameters.

Consider requiring _registry != address(0) or checking if _initialCredentialId is empty. This helps avoid deploying an account with an invalid registry reference or missing admin credential.

+ require(_registry != address(0), "Registry address cannot be zero");
+ require(_initialCredentialId.length != 0, "Initial credential cannot be empty");

607-629: Confirm skipping user verification is intended.

Currently, requireUserVerification: false might allow credentials without user presence checks. If user verification is required, adjust your WebAuthn signature checks to match stricter security needs.


557-573: Execution logic appears correct.

execute properly checks signatures, handles reverts, and increments the nonce. No issues found with concurrency or security here.


703-711: Interface support is accurately declared.

The contract correctly reports support for ERC1155Receiver, ERC721Receiver, and ERC1271, and rejects unknown interface IDs.


549-554: Pause validation is streamlined.

The whenNotPaused modifier reverts on paused state using AccountIsPaused for clarity. This effectively blocks execution calls when the contract is paused.


728-735: Double-check indefinite pause assignment.

When _until == 0, the contract assigns type(uint256).max to pausedUntil. Verify that an indefinite pause meets the project’s operational and support needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants