Skip to content

Conversation

@RanaBug
Copy link
Contributor

@RanaBug RanaBug commented Nov 4, 2025

Description

  • Added ownerAccount param to TransactionKit, for delegatedEoa mode (either privateKey or ownerAccount)

How Has This Been Tested?

  • Unit tests and manual testing

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Summary by CodeRabbit

  • New Features

    • Delegated EOA mode now accepts an owner account object (viemLocalAccount) as an alternative to a private key; provide either one (not both).
  • Bug Fixes

    • Improved validation, error messages, and caching for delegated EOA mode when neither or both credentials are supplied; ensures consistent owner-account resolution under concurrent and mode-switch scenarios.
  • Documentation

    • README and changelog updated with examples, workflow notes, and security guidance for privateKey vs owner-account usage.
  • Chore

    • Release bumped to 2.1.2.

@RanaBug RanaBug requested a review from IAmKio November 4, 2025 17:14
@RanaBug RanaBug self-assigned this Nov 4, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

Adds support for passing a viem LocalAccount (viemLocalAccount) as an alternative to privateKey in delegatedEoa mode, enforces mutual-exclusion/validation and update-time checks, updates types, tests, docs, sanitization keys, and bumps version to 2.1.2.

Changes

Cohort / File(s) Summary
Changelog & Version
CHANGELOG.md, package.json
Bumped package version to 2.1.2. Changelog documents support for viemLocalAccount as an alternative to privateKey in delegatedEoa mode.
Documentation
README.md
Examples, notes, Wallet Mode Comparison, and security guidance updated to reference viemLocalAccount alongside privateKey and clarify mutual-exclusion and provider usage.
Type Definitions
lib/interfaces/index.ts
Import LocalAccount from viem; added viemLocalAccount?: LocalAccount to PrivateConfig; DelegatedEoaModeConfig now accepts either privateKey?: string or viemLocalAccount?: LocalAccount (mutually exclusive).
Core Implementation
lib/EtherspotProvider.ts
delegatedEoa validation now requires exactly one of privateKey or viemLocalAccount; updateConfig enforces post-update state and clears the opposite field when switching; getOwnerAccount returns the provided viemLocalAccount or creates one from privateKey; logging updated to reflect choices.
Utilities
lib/utils/index.ts
SENSITIVE_KEYS expanded to include viemLocalAccount (array reformatted to multi-line).
Tests
__tests__/EtherspotProvider.test.ts
Tests added/updated to cover acceptance of viemLocalAccount, mutual-exclusion errors (both/none), updateConfig switching behavior, cache/concurrency for owner resolution, and ensuring provided viemLocalAccount is returned as the same object.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Provider
  participant Config
  Note over Caller,Provider: Request requiring owner account (delegatedEoa)
  Caller->>Provider: getOwnerAccount()
  Provider->>Config: read delegatedEoa config
  alt viemLocalAccount provided
    Provider->>Provider: return provided viemLocalAccount (cached)
    Provider-->>Caller: LocalAccount (same object)
  else privateKey provided
    Provider->>Provider: create LocalAccount from privateKey
    Provider-->>Caller: created LocalAccount
  else neither or both provided
    Provider-->>Caller: throw validation error
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

  • Review mutual-exclusion validation in lib/EtherspotProvider.ts (creation, updateConfig, and error messages).
  • Verify getOwnerAccount returns the exact provided viemLocalAccount object and caching/concurrency behavior in tests.
  • Confirm LocalAccount import/typing from viem is correct and that sensitive-key redaction includes viemLocalAccount.

Poem

🐇 I found a key and found a friend,
A LocalAccount that hops to lend,
One path chosen, the other sealed,
Delegation now neatly revealed.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'feat/owner-account-param' is vague and does not clearly convey what the main change is; it uses a branch naming convention rather than a descriptive summary. Use a clear, descriptive title that explains the main change, such as 'Allow viemLocalAccount as alternative to privateKey in delegatedEoa mode' or 'Add support for viemLocalAccount parameter in delegated EOA'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is largely complete with all required template sections filled out, though it uses 'ownerAccount' terminology while the actual implementation uses 'viemLocalAccount'.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/owner-account-param

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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 (3)
README.md (1)

112-123: Consider adding an ownerAccount example.

Thanks for calling out that either privateKey or ownerAccount can be supplied, but the sample still only shows the private key path. A short code block demonstrating ownerAccount: someLocalAccount (and omitting privateKey) would make the new workflow immediately copy‑pastable and prevent readers from assuming the flag is still mandatory.

lib/interfaces/index.ts (1)

55-65: Tighten the delegatedEoa config type.

Runtime now rejects configs that pass both privateKey and ownerAccount, but the interface still allows it at compile time. We can align the type with the runtime guard by switching to a discriminated union, so consumers get an immediate TypeScript error if they try to provide both (or neither) fields.

-export interface DelegatedEoaModeConfig {
-  chainId: number;
-  bundlerApiKey?: string;
-  bundlerUrl?: string;
-  bundlerApiKeyFormat?: string;
-  debugMode?: boolean;
-  walletMode: 'delegatedEoa';
-  // Either privateKey or ownerAccount must be provided (but not both)
-  privateKey?: string;
-  ownerAccount?: LocalAccount;
-}
+type DelegatedEoaCredentials =
+  | { privateKey: string; ownerAccount?: never }
+  | { ownerAccount: LocalAccount; privateKey?: never };
+
+export type DelegatedEoaModeConfig = {
+  chainId: number;
+  bundlerApiKey?: string;
+  bundlerUrl?: string;
+  bundlerApiKeyFormat?: string;
+  debugMode?: boolean;
+  walletMode: 'delegatedEoa';
+} & DelegatedEoaCredentials;
__tests__/EtherspotProvider.test.ts (1)

1066-1083: Refactor: Test is misplaced or redundant.

This test is located in the getOwnerAccount describe block but actually tests updateConfig validation. It's also redundant with the test at lines 463-480, which already covers the same scenario of throwing when both parameters are cleared.

Consider either:

  • Moving this test to the "updateConfig with delegatedEoa mode and ownerAccount" describe block (lines 359-481), or
  • Removing it as redundant, or
  • Refactoring it to actually test getOwnerAccount's error handling (though that would require the provider to be in an invalid state, which the constructor/updateConfig prevent)

Apply this diff to remove the redundant test:

-      it('should throw when neither ownerAccount nor privateKey is available', () => {
-        const delegated = new EtherspotProvider({
-          chainId: 1,
-          walletMode: 'delegatedEoa',
-          privateKey:
-            '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
-        } as EtherspotTransactionKitConfig);
-
-        expect(() => {
-          delegated.updateConfig({
-            walletMode: 'delegatedEoa',
-            privateKey: undefined,
-            ownerAccount: undefined,
-          });
-        }).toThrow(
-          'Either privateKey or ownerAccount is required when walletMode is "delegatedEoa"'
-        );
-      });
-
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44d06f8 and eed1747.

📒 Files selected for processing (7)
  • CHANGELOG.md (1 hunks)
  • README.md (8 hunks)
  • __tests__/EtherspotProvider.test.ts (13 hunks)
  • lib/EtherspotProvider.ts (7 hunks)
  • lib/interfaces/index.ts (3 hunks)
  • lib/utils/index.ts (1 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
__tests__/EtherspotProvider.test.ts (2)
lib/EtherspotProvider.ts (1)
  • EtherspotProvider (50-824)
lib/interfaces/index.ts (1)
  • EtherspotTransactionKitConfig (68-70)
lib/EtherspotProvider.ts (2)
lib/interfaces/index.ts (2)
  • EtherspotTransactionKitConfig (68-70)
  • DelegatedEoaModeConfig (55-65)
lib/utils/index.ts (1)
  • log (70-75)
🔇 Additional comments (10)
__tests__/EtherspotProvider.test.ts (10)

8-8: LGTM: Import addition is appropriate.

The privateKeyToAccount import from viem/accounts is correctly added to support the new ownerAccount test scenarios.


193-254: LGTM: Comprehensive constructor validation tests.

The new tests thoroughly validate the mutual exclusivity requirement for privateKey and ownerAccount in delegatedEoa mode:

  • Correctly rejects when neither is provided
  • Correctly rejects when both are provided
  • Correctly accepts when only ownerAccount is provided
  • Error messages are accurate and helpful

359-481: LGTM: Excellent coverage of updateConfig with ownerAccount.

The new test suite comprehensively covers all updateConfig scenarios:

  • Switching between privateKey and ownerAccount correctly clears the opposite field
  • Correctly verifies object identity when ownerAccount is provided (line 400: expect(owner).toBe(newOwnerAccount))
  • Correctly verifies address changes when switching to privateKey (lines 422-426)
  • Validates all error conditions (neither, both, clearing both)

The tests properly distinguish between the two modes of operation and verify the expected behavior in each case.


1042-1054: LGTM: Correct verification of ownerAccount passthrough.

This test properly verifies that when an ownerAccount is provided, getOwnerAccount() returns the exact same object (not a copy). The use of toBe on line 1053 is essential to confirm object identity.


1110-1134: LGTM: Excellent concurrent access test.

This test correctly verifies that concurrent calls to getOwnerAccount() with a provided ownerAccount all return the exact same object. The use of toBe (lines 1131-1133) is crucial to verify object identity rather than just equality.


1085-1108: LGTM: Correct test for privateKey concurrent access.

The test correctly verifies that concurrent calls to getOwnerAccount() with privateKey all return accounts with the same address (lines 1105-1107). The comment on line 1104 accurately describes the expected behavior.

Note: This appropriately contrasts with lines 1110-1134, where the ownerAccount case verifies object identity using toBe. With privateKey, each call creates a new LocalAccount object (via privateKeyToAccount), so only address equality is verified.


1176-1190: LGTM: Good integration test for ownerAccount support.

This test correctly verifies that getDelegatedEoaAccount works properly when an ownerAccount is provided directly. The verification at line 1189 (expect(owner).toBe(ownerAccount)) confirms that the same object is used throughout the flow.


1423-1439: LGTM: Cache clearing with ownerAccount is properly tested.

This test correctly verifies that switching to delegatedEoa mode with an ownerAccount (instead of privateKey) also clears caches appropriately. It mirrors the existing test at lines 1407-1421, providing symmetric coverage for both parameter types.


1472-1483: LGTM: Error message consistently updated.

The test correctly verifies the updated error message that reflects the dual-parameter support (either privateKey or ownerAccount). The error message is consistent with other validation tests throughout the file.


888-897: LGTM: Test correctly updated for new validation.

The test now explicitly provides a privateKey when switching to delegatedEoa mode, as required by the new validation logic. This maintains the test's original intent while complying with the enhanced parameter requirements.

Copy link
Contributor

@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 (1)
lib/EtherspotProvider.ts (1)

172-178: Minor: Comment and type assertion could be clearer.

The comment on line 172 says "Store viemLocalAcocunt address as string for comparison (not in DelegatedEoaModeConfig type)" but line 178 includes a type assertion adding ownerAccountAddress to the type. This is slightly confusing.

Consider either:

  1. Documenting that we're extending the type for internal comparison purposes, or
  2. Creating a separate internal type for this comparison object
-      // Store viemLocalAcocunt address as string for comparison (not in DelegatedEoaModeConfig type)
+      // Store viemLocalAccount address for comparison (extended type for internal use)
       viemLocalAcocuntAddress: delegatedEoaConfig.viemLocalAcocunt?.address,
       bundlerUrl: delegatedEoaConfig.bundlerUrl,
       bundlerApiKey: delegatedEoaConfig.bundlerApiKey,
       bundlerApiKeyFormat: delegatedEoaConfig.bundlerApiKeyFormat,
       walletMode: 'delegatedEoa',
-    } as DelegatedEoaModeConfig & { ownerAccountAddress?: string };
+    } as DelegatedEoaModeConfig & { viemLocalAcocuntAddress?: string };

Note: The property name in the type assertion should match the actual property name used on line 173.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eed1747 and 2c5438f.

📒 Files selected for processing (6)
  • CHANGELOG.md (1 hunks)
  • README.md (9 hunks)
  • __tests__/EtherspotProvider.test.ts (13 hunks)
  • lib/EtherspotProvider.ts (7 hunks)
  • lib/interfaces/index.ts (3 hunks)
  • lib/utils/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/utils/index.ts
  • lib/interfaces/index.ts
🧰 Additional context used
🧬 Code graph analysis (2)
__tests__/EtherspotProvider.test.ts (2)
lib/EtherspotProvider.ts (1)
  • EtherspotProvider (50-825)
lib/interfaces/index.ts (1)
  • EtherspotTransactionKitConfig (68-70)
lib/EtherspotProvider.ts (2)
lib/interfaces/index.ts (2)
  • EtherspotTransactionKitConfig (68-70)
  • DelegatedEoaModeConfig (55-65)
lib/utils/index.ts (1)
  • log (70-75)
🪛 LanguageTool
README.md

[grammar] ~449-~449: Ensure spelling is correct
Context: ... from viem) directly, but not both. The viemLocalAcocunt option is useful when you already have ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~612-~612: Ensure spelling is correct
Context: ... 7. Owner Account Usage: When using viemLocalAcocunt, ensure the underlying private key is h...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (5)
README.md (1)

1-670: Skip: Duplicate issue already flagged.

The typo viemLocalAcocuntviemLocalAccount appears throughout this file and has already been flagged in the CHANGELOG.md review. Please apply the same fix to all occurrences in this file.

__tests__/EtherspotProvider.test.ts (1)

1-1629: Skip: Duplicate issue already flagged.

The typo viemLocalAcocuntviemLocalAccount appears throughout this test file. This has already been flagged in the CHANGELOG.md review. Please apply the same fix to all test names, variables, and assertions in this file.

lib/EtherspotProvider.ts (3)

1-825: Skip: Duplicate issue already flagged.

The typo viemLocalAcocuntviemLocalAccount appears throughout this implementation file. This has already been flagged in the CHANGELOG.md review. Please apply the same fix to all occurrences including variable names, parameter names, JSDoc comments, error messages, and log messages.


213-246: Approve the mutual exclusivity logic.

The validation logic correctly ensures that:

  1. In delegatedEoa mode, at least one of privateKey or viemLocalAccount must be provided
  2. Both cannot be provided simultaneously
  3. The clearing logic properly handles switching between the two options

The implementation correctly accounts for the clearing behavior when calculating willHavePrivateKey and willHaveViemLocalAccount, preventing invalid states.


568-596: Approve the getOwnerAccount implementation.

The implementation correctly:

  1. Returns the provided viemLocalAccount directly if available (avoiding unnecessary conversion)
  2. Falls back to creating an account from privateKey if no viemLocalAccount is provided
  3. Includes appropriate logging for both paths
  4. Throws a clear error if neither is available

This design is efficient and aligns with the PR objectives.

CHANGELOG.md Outdated

### Added Changes

- **viemLocalAcocunt Support**: Added support for passing a `LocalAccount` (from viem) directly to the Transaction Kit via the `viemLocalAcocunt` parameter in `delegatedEoa` mode. This allows users to bypass `privateKeyToAccount` conversion when they already have a `LocalAccount` object. The `viemLocalAcocunt` parameter works equivalently to `privateKey` and provides the same functionality - users can provide either `privateKey` or `viemLocalAcocunt`, but not both.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

CRITICAL: Fix typo in parameter name before release.

The parameter name viemLocalAcocunt contains a typo and should be viemLocalAccount (note the "cc" vs "cc" → should be "ccount"). This typo appears throughout the entire codebase including public API, documentation, tests, and error messages.

This is critical because:

  1. It's a public API parameter - fixing it after release would be a breaking change
  2. The correct spelling aligns with viem's LocalAccount type
  3. It affects developer experience and code professionalism

Apply this fix across the entire codebase by replacing all instances of viemLocalAcocunt with viemLocalAccount:

-- **viemLocalAcocunt Support**: Added support for passing a `LocalAccount` (from viem) directly to the Transaction Kit via the `viemLocalAcocunt` parameter in `delegatedEoa` mode. This allows users to bypass `privateKeyToAccount` conversion when they already have a `LocalAccount` object. The `viemLocalAcocunt` parameter works equivalently to `privateKey` and provides the same functionality - users can provide either `privateKey` or `viemLocalAcocunt`, but not both.
+- **viemLocalAccount Support**: Added support for passing a `LocalAccount` (from viem) directly to the Transaction Kit via the `viemLocalAccount` parameter in `delegatedEoa` mode. This allows users to bypass `privateKeyToAccount` conversion when they already have a `LocalAccount` object. The `viemLocalAccount` parameter works equivalently to `privateKey` and provides the same functionality - users can provide either `privateKey` or `viemLocalAccount`, but not both.

This needs to be fixed in:

  • CHANGELOG.md
  • README.md (multiple occurrences)
  • lib/EtherspotProvider.ts (implementation)
  • lib/interfaces/index.ts (type definitions)
  • lib/utils/index.ts (SENSITIVE_KEYS)
  • tests/EtherspotProvider.test.ts (all test cases)
📝 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
- **viemLocalAcocunt Support**: Added support for passing a `LocalAccount` (from viem) directly to the Transaction Kit via the `viemLocalAcocunt` parameter in `delegatedEoa` mode. This allows users to bypass `privateKeyToAccount` conversion when they already have a `LocalAccount` object. The `viemLocalAcocunt` parameter works equivalently to `privateKey` and provides the same functionality - users can provide either `privateKey` or `viemLocalAcocunt`, but not both.
- **viemLocalAccount Support**: Added support for passing a `LocalAccount` (from viem) directly to the Transaction Kit via the `viemLocalAccount` parameter in `delegatedEoa` mode. This allows users to bypass `privateKeyToAccount` conversion when they already have a `LocalAccount` object. The `viemLocalAccount` parameter works equivalently to `privateKey` and provides the same functionality - users can provide either `privateKey` or `viemLocalAccount`, but not both.
🤖 Prompt for AI Agents
In CHANGELOG.md around line 7, the public parameter name `viemLocalAcocunt` is
misspelled and must be corrected to `viemLocalAccount`; update this line and
then perform a project-wide rename of the identifier (code, docs, tests, types,
and SENSITIVE_KEYS) replacing all occurrences of `viemLocalAcocunt` with
`viemLocalAccount` (including README.md, lib/EtherspotProvider.ts,
lib/interfaces/index.ts, lib/utils/index.ts, and
__tests__/EtherspotProvider.test.ts), update any exported names/signatures and
error messages to the correct spelling, and run/update tests to reflect the new
name; if you need to avoid a breaking change immediately, add a temporary alias
or deprecation wrapper that maps the old misspelled name to the corrected one
and mark it for removal in the next major release.

IAmKio
IAmKio previously approved these changes Nov 5, 2025
Copy link
Contributor

@IAmKio IAmKio left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@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)
README.md (1)

449-458: Consider adding a viemLocalAccount example.

The note explains the option, but every snippet still passes privateKey. A tiny code sample showing viemLocalAccount: yourLocalAccount would make the new flow discoverable without guesswork.

lib/EtherspotProvider.ts (1)

172-183: Fix the type assertion for the viem local account address.

We emit a viemLocalAccountAddress property but assert the shape as { ownerAccountAddress?: string }. That mismatch defeats the compiler’s protection—future code could read ownerAccountAddress and always get undefined. Please align the asserted type (or rename the property) so the shape is truthful.

Apply this diff to align the type:

-    } as DelegatedEoaModeConfig & { ownerAccountAddress?: string };
+    } as DelegatedEoaModeConfig & { viemLocalAccountAddress?: string };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c5438f and d39104e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • CHANGELOG.md (1 hunks)
  • README.md (9 hunks)
  • __tests__/EtherspotProvider.test.ts (14 hunks)
  • lib/EtherspotProvider.ts (7 hunks)
  • lib/interfaces/index.ts (3 hunks)
  • lib/utils/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/interfaces/index.ts
🧰 Additional context used
🧬 Code graph analysis (2)
lib/EtherspotProvider.ts (2)
lib/interfaces/index.ts (2)
  • EtherspotTransactionKitConfig (68-70)
  • DelegatedEoaModeConfig (55-65)
lib/utils/index.ts (1)
  • log (70-75)
__tests__/EtherspotProvider.test.ts (2)
lib/EtherspotProvider.ts (1)
  • EtherspotProvider (50-829)
lib/interfaces/index.ts (1)
  • EtherspotTransactionKitConfig (68-70)
🔇 Additional comments (2)
lib/utils/index.ts (1)

81-86: Sensitive key list update looks correct.

Adding viemLocalAccount ensures LocalAccount objects are redacted alongside the other confidential fields.

__tests__/EtherspotProvider.test.ts (1)

191-252: Great coverage for delegatedEoa credential validation.

The new test cases pin the “neither” and “both” scenarios and prove viemLocalAccount works interchangeably with privateKey, guarding the new config requirements.

@RanaBug RanaBug merged commit 66b5373 into master Nov 5, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants