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

feat: coinbase gas manager #1

Merged
merged 3 commits into from
Feb 15, 2025
Merged

feat: coinbase gas manager #1

merged 3 commits into from
Feb 15, 2025

Conversation

Syn-McJ
Copy link
Owner

@Syn-McJ Syn-McJ commented Feb 15, 2025

Summary by CodeRabbit

  • New Features

    • Introduced Coinbase integration, enabling sponsorship of user operations and enhanced paymaster capabilities for smoother transaction processing.
  • Refactor

    • Streamlined provider and gas management configuration for more reliable fee estimation and improved error reporting, ensuring a more consistent user experience.

Copy link

coderabbitai bot commented Feb 15, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update streamlines provider configuration by consolidating connection settings, renaming configuration types (from AlchemyProviderConfig to ProviderConfig), and updating error handling (replacing AlchemyError with ProviderError). Additionally, method signatures and access levels in RPC and client protocols have been revised (e.g. renaming maxPriorityFeePerGas to eth_maxPriorityFeePerGas). New Coinbase integration has been introduced with dedicated protocols, clients, providers, and sponsorship-related structures, while gas management enhancements and hex utility improvements have also been incorporated.

Changes

File(s) Change Summary
Example/Sources/MainViewModel.swift
Sources/Alchemy/Provider/AlchemyProvider.swift
Sources/Core/Provider/ProviderConfig.swift
Updated provider and gas manager initialization by replacing inline connection configuration with a unified connectionConfig and renaming AlchemyProviderConfig to ProviderConfig.
Sources/Alchemy/Account/Utils.swift
Sources/Alchemy/AlchemyError.swift
Sources/Core/Provider/ProviderError.swift
Sources/Alchemy/Provider/AlchemyProvider.swift
Overhauled error handling: removed AlchemyError enum and replaced thrown errors with the new ProviderError cases.
Sources/Alchemy/Middleware/AlchemyClient.swift
Sources/Alchemy/Middleware/AlchemyRpcClient.swift
Sources/Core/Client/Erc4337Client.swift
Sources/Core/Client/Erc4337RpcClient.swift
Sources/Core/Client/PaymasterAndData.swift
Renamed and updated client method signatures – notably changing return types from AlchemyPaymasterAndData to PaymasterAndData and renaming fee methods to eth_maxPriorityFeePerGas for consistency.
Sources/Alchemy/Middleware/GasManager.swift
Sources/Core/Provider/SmartAccountProvider.swift
Sources/Coinbase/Middleware/GasManager.swift
Enhanced gas management by refactoring estimation logic, introducing a new initializer that accepts connectionConfig, updating method parameters to use SmartAccountProvider, and adding middleware client support.
Sources/Alchemy/Middleware/AlchemyGasAndPaymasterAndData.swift
Sources/Core/Utils/Hex.swift
Modified imports by replacing Foundation with AASwift and added a properHexString property for cleaner hexadecimal representations in user operation requests.
Sources/Alchemy/Chain.swift Adjusted the BaseSepolia URL by removing a trailing slash.
Package.swift
Sources/Coinbase/Chain.swift
Sources/Coinbase/Middleware/CoinbaseClient.swift
Sources/Coinbase/Middleware/CoinbaseRpcClient.swift
Sources/Coinbase/Provider/CoinbaseProvider.swift
Sources/Coinbase/Provider/CreateClient.swift
Sources/Coinbase/Middleware/PaymasterDataParams.swift
Sources/Coinbase/Middleware/SponsorUserOpParams.swift
Sources/Coinbase/Middleware/SponsoredUserOperation.swift
Introduced full Coinbase integration: added a new library and target in Package.swift, defined Coinbase-specific chain configurations, protocols, RPC client, provider, and supplementary data structures for paymaster data and sponsored user operations, including methods for fetching paymaster data and sponsoring user operations.

Sequence Diagram(s)

sequenceDiagram
    participant SA as SmartAccountProvider
    participant CCP as CoinbaseClient (via CoinbaseRpcClient)
    participant NP as Network Provider

    SA->>SA: withCoinbaseGasManager(connectionConfig)
    Note right of SA: Gas estimation middleware triggers
    alt Sponsorship needed
        SA->>CCP: sponsorUserOperation(userOp, entryPoint)
        CCP->>NP: Send "pm_sponsorUserOperation" request
        NP-->>CCP: Return SponsoredUserOperation
        CCP-->>SA: Return paymaster data & sponsorship details
    else
        SA->>CCP: getPaymasterData(params)
        CCP->>NP: Send "pm_getPaymasterStubData" request
        NP-->>CCP: Return PaymasterAndData
        CCP-->>SA: Return paymaster data
    end
    SA->>SA: Update user operation with received values
Loading

Poem

I'm a rabbit with a skip and a hop,
Changes abound, no need to stop!
Configs and errors now streamlined with flair,
Coinbase joins the dance with care.
Gas flows smoother, hex is just right,
CodeRabbit’s magic shines ever so bright!
🥕 Hop along into a cleaner night!


🪧 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. (Beta)
  • @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.

@Syn-McJ
Copy link
Owner Author

Syn-McJ commented Feb 15, 2025

@CodeRabbit review

Copy link

coderabbitai bot commented Feb 15, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 6

🧹 Nitpick comments (14)
Sources/Coinbase/Provider/CoinbaseProvider.swift (1)

12-12: Consider avoiding a static property for rpcUrl to prevent shared global state.

Storing mutable data in a static property can lead to potential race conditions and inadvertent side effects if your code runs in a multi-threaded environment. Consider converting it to an instance-level property or passing the URL directly to consumers.

- private static var rpcUrl: String = ""
+ private var rpcUrl: String
Sources/Coinbase/Middleware/GasManager.swift (1)

56-60: Avoid force-casting the returned value to Self.

Force casting can lead to runtime crashes if the actual type isn't what you expect. Prefer a conditional cast or a generic approach.

- return withMiddlewareRpcClient(
-     rpcClient: try CoinbaseProvider.createRpcClient(
-         config: ProviderConfig(chain: chain, connectionConfig: connectionConfig)
-     )
- ) as! Self
+ guard let typedSelf = withMiddlewareRpcClient(
+     rpcClient: try CoinbaseProvider.createRpcClient(
+         config: ProviderConfig(chain: chain, connectionConfig: connectionConfig)
+     )
+ ) as? Self else {
+     throw ProviderError.invalidTypeCasting("Expected type: \(Self.self)")
+ }
+ return typedSelf
🧰 Tools
🪛 SwiftLint (0.57.0)

[Error] 60-60: Force casts should be avoided

(force_cast)

Sources/Alchemy/Middleware/GasManager.swift (2)

103-103: Remove the trailing semicolon.

Swift doesn't require semicolons except in specific edge cases. Keeping the code consistent without them improves readability.

- };
+ }
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 103-103: Lines should not have trailing semicolons

(trailing_semicolon)


107-107: Refactor to avoid force-casting during withMiddlewareRpcClient.

Similar to line 100-102, prefer a safer cast or updated function signature.

- ) as! Self
+ ) as? Self ?? self
🧰 Tools
🪛 SwiftLint (0.57.0)

[Error] 107-107: Force casts should be avoided

(force_cast)

Sources/Coinbase/Middleware/CoinbaseClient.swift (1)

10-13: Add documentation for protocol methods.

The protocol methods would benefit from documentation explaining their purpose, parameters, return values, and possible errors.

Apply this diff to add documentation:

 public protocol CoinbaseClient: Erc4337Client {
+    /// Retrieves paymaster data for a user operation.
+    /// - Parameter params: Parameters containing the user operation details.
+    /// - Returns: Paymaster data for the operation.
+    /// - Throws: Network or validation errors.
     func getPaymasterData(params: PaymasterDataParams) async throws -> PaymasterAndData
+    
+    /// Sponsors a user operation by providing necessary gas fees.
+    /// - Parameters:
+    ///   - userOp: The user operation to sponsor.
+    ///   - entryPoint: The entry point contract address.
+    /// - Returns: The sponsored user operation details.
+    /// - Throws: Network or validation errors.
     func sponsorUserOperation(userOp: UserOperationRequest, entryPoint: String) async throws -> SponsoredUserOperation
 }
Sources/Coinbase/Middleware/PaymasterDataParams.swift (2)

14-19: Add documentation for the required field order.

The PaymasterDataParams struct looks good, but please add documentation explaining why the fields need to be encoded in a specific order. This will help maintainers understand the requirements of the Coinbase API.


17-17: Consider adding chainId validation.

The chainId is accepted as a String. Consider adding validation to ensure it matches Coinbase's expected format, or consider using a more specific type if possible.

Sources/Coinbase/Chain.swift (1)

2-2: Update the copyright year.

The copyright year should be 2024 instead of 2025.

-//  Copyright (c) 2025 aa-swift
+//  Copyright (c) 2024 aa-swift
Sources/Coinbase/Middleware/CoinbaseRpcClient.swift (2)

12-23: Simplify error handling and type casting.

The current implementation has redundant type casting and could benefit from simplified error handling.

Consider this simplified version:

 public func getPaymasterData(params: PaymasterDataParams) async throws -> PaymasterAndData {
-    do {
-        let data = try await networkProvider.send(method: "pm_getPaymasterStubData", params: params, receive: PaymasterAndData.self)
-        if let result = data as? PaymasterAndData {
-            return result
-        } else {
-            throw EthereumClientError.unexpectedReturnValue
-        }
-    } catch {
-        throw failureHandler(error)
-    }
+    try await networkProvider.send(
+        method: "pm_getPaymasterStubData",
+        params: params,
+        receive: PaymasterAndData.self
+    )
 }

The send method already returns the correct type, making the type cast unnecessary.


25-37: Apply the same simplification to sponsorUserOperation.

This method can benefit from the same simplifications as getPaymasterData.

 public func sponsorUserOperation(userOp: UserOperationRequest, entryPoint: String) async throws -> SponsoredUserOperation {
-    do {
-        let params = SponsorUserOpParams(userOperation: userOp, entryPoint: entryPoint)
-        let data = try await networkProvider.send(method: "pm_sponsorUserOperation", params: params, receive: SponsoredUserOperation.self)
-        if let result = data as? SponsoredUserOperation {
-            return result
-        } else {
-            throw EthereumClientError.unexpectedReturnValue
-        }
-    } catch {
-        throw failureHandler(error)
-    }
+    let params = SponsorUserOpParams(userOperation: userOp, entryPoint: entryPoint)
+    try await networkProvider.send(
+        method: "pm_sponsorUserOperation",
+        params: params,
+        receive: SponsoredUserOperation.self
+    )
 }
Sources/Alchemy/Provider/AlchemyProvider.swift (1)

16-35: Improve URL construction logic.

The URL construction could be simplified and made more robust.

Consider using URL components:

-guard let rpcUrl = config.connectionConfig.rpcUrl ?? (chain.alchemyRpcHttpUrl.map {
-    let apiKey = config.connectionConfig.apiKey ?? ""
-    return apiKey.isEmpty ? $0 : "\($0)/\(apiKey)"
-}) else {
+guard let baseUrl = config.connectionConfig.rpcUrl ?? chain.alchemyRpcHttpUrl,
+      var components = URLComponents(string: baseUrl) else {
     throw ProviderError.rpcUrlNotFound("No rpcUrl found for chain \(config.chain.id)")
+}
+
+if let apiKey = config.connectionConfig.apiKey, !apiKey.isEmpty {
+    components.path = components.path.trimmingCharacters(in: .init(charactersIn: "/"))
+    components.path += "/\(apiKey)"
+}
+
+guard let rpcUrl = components.string else {
+    throw ProviderError.rpcUrlNotFound("Invalid URL construction for chain \(config.chain.id)")
 }
Sources/Core/Provider/SmartAccountProvider.swift (3)

23-23: Remove redundant nil initialization.

The explicit nil initialization is redundant as optional properties are automatically initialized to nil.

-    private var middlewareClient: Erc4337Client? = nil
+    private var middlewareClient: Erc4337Client?
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 23-23: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)


23-23: Remove redundant nil initialization.

Optional variables are automatically initialized to nil in Swift.

-    private var middlewareClient: Erc4337Client? = nil
+    private var middlewareClient: Erc4337Client?
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 23-23: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)


23-23: Remove redundant nil initialization.

The initialization with nil is redundant as optional variables are automatically initialized with nil.

-    private var middlewareClient: Erc4337Client? = nil
+    private var middlewareClient: Erc4337Client?
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 23-23: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 785e527 and 3ec90b4.

📒 Files selected for processing (26)
  • Example/Sources/MainViewModel.swift (1 hunks)
  • Package.swift (2 hunks)
  • Sources/Alchemy/Account/Utils.swift (1 hunks)
  • Sources/Alchemy/AlchemyError.swift (0 hunks)
  • Sources/Alchemy/Chain.swift (1 hunks)
  • Sources/Alchemy/Middleware/AlchemyClient.swift (1 hunks)
  • Sources/Alchemy/Middleware/AlchemyGasAndPaymasterAndData.swift (1 hunks)
  • Sources/Alchemy/Middleware/AlchemyRpcClient.swift (2 hunks)
  • Sources/Alchemy/Middleware/GasManager.swift (6 hunks)
  • Sources/Alchemy/Provider/AlchemyProvider.swift (2 hunks)
  • Sources/Coinbase/Chain.swift (1 hunks)
  • Sources/Coinbase/Middleware/CoinbaseClient.swift (1 hunks)
  • Sources/Coinbase/Middleware/CoinbaseRpcClient.swift (1 hunks)
  • Sources/Coinbase/Middleware/GasManager.swift (1 hunks)
  • Sources/Coinbase/Middleware/PaymasterDataParams.swift (1 hunks)
  • Sources/Coinbase/Middleware/SponsorUserOpParams.swift (1 hunks)
  • Sources/Coinbase/Middleware/SponsoredUserOperation.swift (1 hunks)
  • Sources/Coinbase/Provider/CoinbaseProvider.swift (1 hunks)
  • Sources/Coinbase/Provider/CreateClient.swift (1 hunks)
  • Sources/Core/Client/Erc4337Client.swift (1 hunks)
  • Sources/Core/Client/Erc4337RpcClient.swift (3 hunks)
  • Sources/Core/Client/PaymasterAndData.swift (1 hunks)
  • Sources/Core/Provider/ProviderConfig.swift (1 hunks)
  • Sources/Core/Provider/ProviderError.swift (1 hunks)
  • Sources/Core/Provider/SmartAccountProvider.swift (5 hunks)
  • Sources/Core/Utils/Hex.swift (1 hunks)
💤 Files with no reviewable changes (1)
  • Sources/Alchemy/AlchemyError.swift
✅ Files skipped from review due to trivial changes (2)
  • Sources/Alchemy/Chain.swift
  • Sources/Alchemy/Middleware/AlchemyGasAndPaymasterAndData.swift
👮 Files not reviewed due to content moderation or server errors (3)
  • Sources/Core/Client/Erc4337RpcClient.swift
  • Example/Sources/MainViewModel.swift
  • Sources/Core/Provider/SmartAccountProvider.swift
🧰 Additional context used
🪛 SwiftLint (0.57.0)
Sources/Core/Provider/SmartAccountProvider.swift

[Warning] 23-23: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

Sources/Coinbase/Middleware/GasManager.swift

[Error] 60-60: Force casts should be avoided

(force_cast)

Sources/Alchemy/Middleware/GasManager.swift

[Error] 100-100: Force casts should be avoided

(force_cast)


[Error] 102-102: Force casts should be avoided

(force_cast)


[Error] 107-107: Force casts should be avoided

(force_cast)


[Warning] 103-103: Lines should not have trailing semicolons

(trailing_semicolon)


[Error] 131-131: Force casts should be avoided

(force_cast)

🔇 Additional comments (35)
Sources/Core/Utils/Hex.swift (2)

15-22: LGTM! Great improvement in hex string handling.

The new properHexString property enhances hex string representation by ensuring consistent formatting, especially for zero values. The implementation is clean and handles edge cases appropriately.


28-35: LGTM! Consistent hex string formatting across all numeric fields.

The changes improve consistency by using properHexString for all numeric fields while maintaining appropriate fallback values for each field type.

Sources/Coinbase/Provider/CoinbaseProvider.swift (1)

38-41: Clarify the purpose of passing nil for rpcUrl in the superclass initializer.

You set CoinbaseProvider.rpcUrl in createRpcClient but pass nil to the super.init call for rpcUrl. If SmartAccountProvider requires this value for functionality (like logging or error messages), you might consider passing the actual rpcUrl instead of nil for clearer intent.

Sources/Core/Provider/ProviderError.swift (1)

8-12: LGTM! Well-structured error handling.

The error cases are well-defined with descriptive names and associated values for context.

Sources/Alchemy/Middleware/AlchemyClient.swift (1)

13-13: LGTM! Good move towards provider-agnostic types.

The change to use PaymasterAndData instead of AlchemyPaymasterAndData improves modularity by making the return type provider-agnostic. This aligns well with supporting multiple providers like Coinbase.

Sources/Core/Provider/ProviderConfig.swift (1)

8-8: LGTM! Good abstraction of provider configuration.

The rename from AlchemyProviderConfig to ProviderConfig creates a more generic configuration structure that can be used across different providers. This improves code reusability and maintains a clean abstraction.

Sources/Core/Client/PaymasterAndData.swift (1)

21-21: LGTM! Good standardization of paymaster response type.

The rename from AlchemyPaymasterAndData to PaymasterAndData creates a standardized response type that can be used across different paymaster implementations. This improves consistency and interoperability between different providers.

Sources/Coinbase/Middleware/PaymasterDataParams.swift (2)

10-12: LGTM! Clean Policy structure implementation.

The Policy struct provides a clear and simple representation of Coinbase policy information.


20-26: LGTM! Clean encoding implementation.

The custom encode(to:) implementation ensures the correct field order required by Coinbase's API.

Sources/Coinbase/Chain.swift (1)

10-13: LGTM!

The supported chains mapping is well-structured and correctly typed.

Sources/Coinbase/Middleware/SponsoredUserOperation.swift (2)

10-18: LGTM!

The error structure is well-defined with appropriate protocol conformance.


20-38: Explain access level choices.

The structure has inconsistent access levels - some properties are public while others are internal. Please document the reasoning behind these choices or make them consistent.

Sources/Alchemy/Provider/AlchemyProvider.swift (1)

37-41: LGTM!

The initialization changes align well with the updated configuration structure.

Sources/Alchemy/Middleware/AlchemyRpcClient.swift (2)

14-27: LGTM! Access level change aligns with protocol update.

The change from override to public access level is consistent with the protocol method rename in Erc4337Client.swift.


29-40:

❓ Verification inconclusive

Verify the impact of return type change.

The return type change from AlchemyPaymasterAndData to PaymasterAndData looks good, but let's verify that all callers handle the new type correctly.


🏁 Script executed:

#!/bin/bash
# Search for usages of AlchemyPaymasterAndData to ensure they've been updated
rg "AlchemyPaymasterAndData" -A 5

Length of output: 33


Action Required: Confirm Callers Handle New Return Type

No references to the old type “AlchemyPaymasterAndData” were found, which is a positive sign. However, please manually verify that all callers of the requestPaymasterAndData function correctly handle the new return type PaymasterAndData. Specifically, ensure that:

  • Any instance where the return value is used (or cast) is updated accordingly.
  • There are no implicit assumptions in type handling that might inadvertently rely on properties or behaviors specific to the old type.

Once you’ve confirmed that the new type is correctly handled everywhere, this function update can be fully approved.

Package.swift (2)

23-25: LGTM! New library configuration is consistent.

The new Coinbase library follows the same pattern as existing libraries.


52-61: LGTM! Target configuration matches existing patterns.

The new AASwiftCoinbase target:

  • Follows the same dependency pattern as other targets
  • Uses consistent path and sources configuration
Sources/Alchemy/Account/Utils.swift (1)

54-54: LGTM! Error type change aligns with provider-agnostic approach.

The change from AlchemyError to ProviderError is part of a broader reorganization to make error handling more generic and provider-agnostic.

Sources/Core/Client/Erc4337Client.swift (1)

56-56: LGTM! Method rename follows Ethereum JSON-RPC naming convention.

The rename from maxPriorityFeePerGas to eth_maxPriorityFeePerGas aligns with standard Ethereum JSON-RPC method naming patterns.

Sources/Core/Client/Erc4337RpcClient.swift (6)

98-111: LGTM! Method name now follows Ethereum JSON-RPC naming convention.

The renaming of maxPriorityFeePerGas to eth_maxPriorityFeePerGas better aligns with standard Ethereum JSON-RPC method naming conventions.


114-118: LGTM! Improved handling of baseFeeMultiplier.

The changes enhance the handling of baseFeeMultiplier by:

  1. Using nil coalescing for a default value of 1.2
  2. Adding validation to ensure it's greater than 1

98-111: LGTM! Method name now follows Ethereum's JSON-RPC convention.

The renaming from maxPriorityFeePerGas to eth_maxPriorityFeePerGas better aligns with Ethereum's JSON-RPC method naming convention.


114-118: LGTM! Improved validation logic for baseFeeMultiplier.

The changes enhance the validation logic by:

  1. Setting a default value of 1.2 when baseFeeMultiplier is nil
  2. Ensuring the value is greater than 1

98-111: LGTM! Method name now follows Ethereum's JSON-RPC convention.

The renaming from maxPriorityFeePerGas to eth_maxPriorityFeePerGas better aligns with Ethereum's JSON-RPC method naming convention.


114-118: LGTM! Improved validation logic for baseFeeMultiplier.

The changes enhance the validation logic by:

  1. Setting a default value of 1.2 when baseFeeMultiplier is nil
  2. Ensuring the value is greater than 1
Example/Sources/MainViewModel.swift (3)

152-162: LGTM! Improved configuration management.

The changes enhance code maintainability by:

  1. Consolidating connection settings into a shared connectionConfig
  2. Reusing the same configuration for both provider and gas manager

152-162: LGTM! Improved configuration management.

The changes enhance code maintainability by:

  1. Extracting connection configuration into a reusable variable
  2. Using the same configuration for both provider and gas manager

152-162: LGTM! Improved configuration management.

The changes enhance code maintainability by:

  1. Consolidating connection settings into a shared connectionConfig variable
  2. Using the new ProviderConfig type consistently
Sources/Core/Provider/SmartAccountProvider.swift (7)

234-237: LGTM! Well-implemented builder pattern.

The new method follows the established builder pattern, allowing for fluent method chaining.


253-253: LGTM! Proper fallback handling for middleware client.

The implementation correctly uses the middleware client when available, falling back to the RPC client when not set.


234-237: LGTM! Well-implemented builder pattern.

The new method follows the builder pattern consistently with other similar methods in the class.


253-253: LGTM! Proper fallback handling for middleware client.

The implementation correctly uses nil coalescing to fall back to the regular client when middleware client is not set.


386-387: LGTM! Improved variable handling in chain function.

The changes enhance readability by properly storing and updating the intermediate result.


234-237: LGTM! Well-designed middleware client integration.

The new method provides a clean way to set an optional middleware client while maintaining a fluent interface.


253-253: LGTM! Proper fallback to default RPC client.

The changes correctly use the middleware client when available, falling back to the default RPC client when not set.

let entryPoint = try provider.getEntryPointAddress()
let params = PaymasterAndDataParams(
policyId: config.policyId,
entryPoint: entryPoint.asString(),
userOperation: uoStruct.toUserOperationRequest()
)
let alchemyClient = provider.rpcClient as! AlchemyClient
let alchemyClient = client as! AlchemyClient
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace the force cast to AlchemyClient with a safer alternative or handle error conditions gracefully.

If the client is not of type AlchemyClient, this will result in a runtime crash. Consider throwing an error or returning early if the cast fails.

- let alchemyClient = client as! AlchemyClient
+ guard let alchemyClient = client as? AlchemyClient else {
+     throw ProviderError.invalidClient("Expected AlchemyClient, got \(type(of: client))")
+ }
📝 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
let alchemyClient = client as! AlchemyClient
guard let alchemyClient = client as? AlchemyClient else {
throw ProviderError.invalidClient("Expected AlchemyClient, got \(type(of: client))")
}
🧰 Tools
🪛 SwiftLint (0.57.0)

[Error] 131-131: Force casts should be avoided

(force_cast)

Comment on lines +100 to +102
requestPaymasterAndData(provider: self, config: config) as! Self
} else {
requestGasAndPaymasterData(provider: self, config: config) as! Self
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid force-casting to Self when returning modified providers.

These force casts may lead to runtime crashes. Consider returning a protocol or base type that encompasses all providers or performing a conditional cast with a fail-safe.

- let provider = if disableGasEstimation {
-     requestPaymasterAndData(provider: self, config: config) as! Self
- } else {
-     requestGasAndPaymasterData(provider: self, config: config) as! Self
- };
+ let providerBase: SmartAccountProvider = if disableGasEstimation {
+     requestPaymasterAndData(provider: self, config: config)
+ } else {
+     requestGasAndPaymasterData(provider: self, config: config)
+ }
+ guard let typedSelf = providerBase as? Self else {
+     throw ProviderError.invalidTypeCasting("Expected type: \(Self.self)")
+ }

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 SwiftLint (0.57.0)

[Error] 100-100: Force casts should be avoided

(force_cast)


[Error] 102-102: Force casts should be avoided

(force_cast)

Comment on lines 5 to 11
public func createCoinbaseClient(
url: String,
chain: Chain,
headers: [String: String] = [:]
) -> CoinbaseClient {
return CoinbaseRpcClient(url: URL(string: url)!, network: EthereumNetwork.custom(String(describing: chain.id)), headers: headers)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove force unwrapping of URL to prevent potential crashes.

The current implementation force unwraps the URL, which could crash the app if an invalid URL is provided.

Apply this diff to safely handle invalid URLs:

-    return CoinbaseRpcClient(url: URL(string: url)!, network: EthereumNetwork.custom(String(describing: chain.id)), headers: headers)
+    guard let validUrl = URL(string: url) else {
+        throw ProviderError.invalidUrl("Invalid URL format: \(url)")
+    }
+    return CoinbaseRpcClient(
+        url: validUrl,
+        network: EthereumNetwork.custom(chain.id.description),
+        headers: headers
+    )

Also, add the following case to ProviderError:

case invalidUrl(String)

Comment on lines 9 to 18
struct SponsorUserOpParams: Equatable, Encodable {
public let userOperation: UserOperationRequest
public let entryPoint: String

func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(userOperation)
try container.encode(entryPoint)
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Make the struct public and document the encoding format.

The struct has public properties but is internal, which seems inconsistent. Also, the encoding format using an unkeyed container should be documented.

Apply this diff to improve visibility and documentation:

-struct SponsorUserOpParams: Equatable, Encodable {
+/// Parameters for sponsoring a user operation.
+/// When encoded, produces an array in the format: [userOperation, entryPoint]
+public struct SponsorUserOpParams: Equatable, Encodable {
     public let userOperation: UserOperationRequest
     public let entryPoint: String
     
+    /// Encodes the parameters as an array in the format: [userOperation, entryPoint]
     func encode(to encoder: Encoder) throws {
         var container = encoder.unkeyedContainer()
         try container.encode(userOperation)
         try container.encode(entryPoint)
     }
 }
📝 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
struct SponsorUserOpParams: Equatable, Encodable {
public let userOperation: UserOperationRequest
public let entryPoint: String
func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(userOperation)
try container.encode(entryPoint)
}
}
/// Parameters for sponsoring a user operation.
/// When encoded, produces an array in the format: [userOperation, entryPoint]
public struct SponsorUserOpParams: Equatable, Encodable {
public let userOperation: UserOperationRequest
public let entryPoint: String
/// Encodes the parameters as an array in the format: [userOperation, entryPoint]
func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(userOperation)
try container.encode(entryPoint)
}
}

Comment on lines +15 to +26
extension Chain {
var coinbasePaymasterAndBundlerUrl: String? {
switch self {
case Chain.Base:
return "https://api.developer.coinbase.com/rpc/v1/base"
case Chain.BaseSepolia:
return "https://api.developer.coinbase.com/rpc/v1/base-sepolia"
default:
return nil
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Move URLs to configuration.

The hardcoded URLs should be moved to a configuration file for better maintainability and to support different environments (e.g., staging, production).

Consider creating a configuration struct:

public struct CoinbaseConfig {
    let baseUrl: String
    let baseSepoliaUrl: String
    
    public static let production = CoinbaseConfig(
        baseUrl: "https://api.developer.coinbase.com/rpc/v1/base",
        baseSepoliaUrl: "https://api.developer.coinbase.com/rpc/v1/base-sepolia"
    )
}

Then update the extension to use the configuration:

 extension Chain {
-    var coinbasePaymasterAndBundlerUrl: String? {
+    func coinbasePaymasterAndBundlerUrl(config: CoinbaseConfig) -> String? {
         switch self {
         case Chain.Base:
-            return "https://api.developer.coinbase.com/rpc/v1/base"
+            return config.baseUrl
         case Chain.BaseSepolia:
-            return "https://api.developer.coinbase.com/rpc/v1/base-sepolia"
+            return config.baseSepoliaUrl
         default:
             return nil
         }
     }
 }

Comment on lines +39 to +49
public var callGasLimit: BigUInt {
return BigUInt(hex: callGasLimitStr)!
}

public var verificationGasLimit: BigUInt {
return BigUInt(hex: verificationGasLimitStr)!
}

public var preVerificationGas: BigUInt {
return BigUInt(hex: preVerificationGasStr)!
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle hex conversion failures safely.

The computed properties use force unwrapping (!) which could lead to runtime crashes if the hex strings are invalid.

Consider using optional chaining or throwing an error:

 public var callGasLimit: BigUInt {
-    return BigUInt(hex: callGasLimitStr)!
+    guard let value = BigUInt(hex: callGasLimitStr) else {
+        // Option 1: Return a default value
+        return BigUInt.zero
+        // Option 2: Throw an error
+        // throw ProviderError.invalidHexString("Invalid hex string for callGasLimit: \(callGasLimitStr)")
+    }
+    return value
 }

Apply similar changes to verificationGasLimit and preVerificationGas.

📝 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
public var callGasLimit: BigUInt {
return BigUInt(hex: callGasLimitStr)!
}
public var verificationGasLimit: BigUInt {
return BigUInt(hex: verificationGasLimitStr)!
}
public var preVerificationGas: BigUInt {
return BigUInt(hex: preVerificationGasStr)!
}
public var callGasLimit: BigUInt {
- return BigUInt(hex: callGasLimitStr)!
+ guard let value = BigUInt(hex: callGasLimitStr) else {
+ // Option 1: Return a default value
+ return BigUInt.zero
+ // Option 2: Throw an error
+ // throw ProviderError.invalidHexString("Invalid hex string for callGasLimit: \(callGasLimitStr)")
+ }
+ return value
}
public var verificationGasLimit: BigUInt {
- return BigUInt(hex: verificationGasLimitStr)!
+ guard let value = BigUInt(hex: verificationGasLimitStr) else {
+ // Option 1: Return a default value
+ return BigUInt.zero
+ // Option 2: Throw an error
+ // throw ProviderError.invalidHexString("Invalid hex string for verificationGasLimit: \(verificationGasLimitStr)")
+ }
+ return value
}
public var preVerificationGas: BigUInt {
- return BigUInt(hex: preVerificationGasStr)!
+ guard let value = BigUInt(hex: preVerificationGasStr) else {
+ // Option 1: Return a default value
+ return BigUInt.zero
+ // Option 2: Throw an error
+ // throw ProviderError.invalidHexString("Invalid hex string for preVerificationGas: \(preVerificationGasStr)")
+ }
+ return value
}

@Syn-McJ Syn-McJ merged commit 95ac5bc into develop Feb 15, 2025
1 check passed
@Syn-McJ Syn-McJ deleted the feat/coinbase-gas-manager branch February 15, 2025 02:53
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.

1 participant