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

chore: lightningnodeclient #152

Merged
merged 5 commits into from
Jan 18, 2025
Merged

chore: lightningnodeclient #152

merged 5 commits into from
Jan 18, 2025

Conversation

reez
Copy link
Owner

@reez reez commented Jan 17, 2025

Description

Creates a LightningNodeClient similar to how BDKClient wraps BDKService to provide a clean interface for all the service methods.

lightningClient manages a stateful connection to the Lightning node. We create one instance at the app level and pass it down through the view hierarchy.

This ensures:

  • Only one connection to the node
  • Consistent state across the app
  • Proper resource management (start/stop)
  • Event handling from a single source

That's why in LDKNodeMondayApp.swift we create a single instance of .live and pass this same instance down through the views, rather than creating new .live instances everywhere.

This is a common pattern for services that maintain state or connections - you want a single source of truth rather than multiple independent instances.

Notes to the reviewers

In some of the views I had to refactor breaking things up because I kept getting The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions when trying to build, so that's the reason I had to do that (to build!).

Cleaned up some spots that were calling KeyService directly and shouldn't have been.

I just set the DEVELOPMENT_TEAM back to my ID for the moment, if that makes things way more annoying for you lmk.

Testing

  • Receive sats
  • Show seed and delete it and import it
  • SettingsView (getstatus)

Changelog notice

Checklists

All Submissions:

  • I've signed all my commits
  • I have formatted my code with swift-format per .swift-format file

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced a new client interface for Lightning Node Service.
    • Added a live and mock implementation of the Lightning Node Client.
    • Enhanced modularity for accessing Lightning Node functionality.
    • Updated various view models and views to utilize the new Lightning Node Client for improved dependency management.
    • Enhanced testing capabilities by integrating mock clients in debug previews across multiple views.
  • Bug Fixes

    • Resolved issues related to direct access of shared services by transitioning to instance-based clients.
  • Refactor

    • Restructured several view models and views to improve code organization and maintainability.
    • Introduced new components for better separation of concerns within views and view models.
    • Comprehensive restructuring of the SettingsView and ChannelsListView components for improved modularity.

Copy link
Contributor

coderabbitai bot commented Jan 17, 2025

Walkthrough

The changes introduce a new LightningNodeClient struct in the Lightning Service, creating a modular client interface for interacting with the LightningNodeService. This new structure encapsulates various methods related to node operations, including starting/stopping the node, managing addresses, balances, channels, and payments. The implementation provides both a live instance that directly interacts with the shared service and a mock instance for testing purposes, enhancing the code's flexibility and testability.

Changes

File Change Summary
LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift - Added LightningNodeClient struct
- Created live static instance for direct service interaction
- Added mock static instance for testing
LDKNodeMonday/App/LDKNodeMondayApp.swift - Added private let lightningClient: LightningNodeClient = .live
- Updated methods to use lightningClient instead of LightningNodeService.shared
LDKNodeMonday/View Model/Home/BitcoinViewModel.swift - Added let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Home/OnboardingViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Home/Payments/PaymentsViewModel.swift - Added init(lightningClient: LightningNodeClient)
- Updated listPayments to use lightningClient
LDKNodeMonday/View Model/Home/Receive/BIP21ViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Home/Receive/JITInvoiceViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Home/Send/AmountViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Channel/ChannelAddViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Channel/ChannelsListViewModel.swift - Added let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Danger/SeedViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Peer/DisconnectViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift - Added private let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/Peer/PeersListViewModel.swift - Added let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift - Added let lightningClient: LightningNodeClient
- Updated initializer to accept lightningClient
- Modified methods to use lightningClient
LDKNodeMonday/View/Home/BitcoinView.swift - Updated view model initializations to include lightningClient
LDKNodeMonday/View/Home/OnboardingView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Home/Payments/PaymentsView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Home/Receive/BIP21View.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Home/Receive/JITInvoiceView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Home/Receive/ReceiveView.swift - Added let lightningClient: LightningNodeClient
- Updated view model initializations to include lightningClient
LDKNodeMonday/View/Home/Send/AmountView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift - Updated view model initialization to include lightningClient
- Added ChannelRow struct
LDKNodeMonday/View/Settings/Danger/SeedView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Settings/Peers/PeerView.swift - Updated view model initialization to include lightningClient
LDKNodeMonday/View/Settings/Peers/PeersListView.swift - Updated view model initialization to include lightningClient
- Added PeersList, PeerRow, and ConnectionStatus structs
LDKNodeMonday/View/Settings/SettingsView.swift - Introduced SettingsFormView and related sections for better modularity

Possibly related PRs

  • chore: handle remaining error states #100: This PR modifies error handling in LightningNodeService.swift, which is directly related to the changes made in the main PR that introduces a new struct LightningNodeClient that interacts with LightningNodeService.
  • Network specific storage paths #149: This PR involves modifications to LightningNodeService.swift, including improvements in error handling during initialization, which aligns with the changes in the main PR that enhance the structure and functionality of the LightningNodeService.
  • Appstate for startup and onboarding #150: This PR introduces a new state management system in LDKNodeMondayApp.swift, which is relevant as it affects how the lightningClient is utilized throughout the application, including in the context of the changes made in the main PR.

Poem

🐰 A Lightning Node, a rabbit's delight,
With client so clean, code shining bright
Closures dancing, methods so neat
Testing made simple, oh what a treat!
CodeRabbit hops, refactoring with glee 🌩️


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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.

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 (3)
LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (3)

274-300: LGTM! Consider improving parameter names for better clarity.

The client interface is well-structured and provides good separation of concerns. However, some closure parameter names could be more descriptive:

-    let connect: (PublicKey, String, Bool) async throws -> Void
+    let connect: (nodeId: PublicKey, address: String, persist: Bool) async throws -> Void

-    let connectOpenChannel: (PublicKey, String, UInt64, UInt64?, ChannelConfig?, Bool) async throws -> UserChannelId
+    let connectOpenChannel: (nodeId: PublicKey, address: String, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?, announceChannel: Bool) async throws -> UserChannelId

-    let receive: (UInt64, String, UInt32) async throws -> String
+    let receive: (amountSat: UInt64, message: String, expirySec: UInt32) async throws -> String

361-406: Consider documenting mock values and using more realistic test data.

The mock implementation is comprehensive but could benefit from:

  1. Using a real testnet/signet node ID for better test scenarios
  2. Adding comments explaining the chosen mock values
  3. Considering edge cases in mock responses
     static let mock = Self(
         start: { },
         stop: { },
-        nodeId: { "038474837483784378437843784378437843784378" },
+        // Real signet node ID for better test scenarios
+        nodeId: { "0269f78d9adf243864b0ebc137b4f0558f44d2262c9885e5b0ab5f23c1a6d6eec3" },
         newAddress: { "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" },
-        spendableOnchainBalanceSats: { 100_000 },
+        // 100k sats = 0.001 BTC
+        spendableOnchainBalanceSats: { 100_000 },
         // ... rest of the implementation
     )

274-406: Add documentation for the client interface.

Consider adding documentation comments to:

  1. The LightningNodeClient struct explaining its purpose and usage
  2. Key properties that might need additional context
  3. Examples of how to use the live and mock implementations
+/// A client interface for interacting with the Lightning Node Service.
+/// 
+/// Use the `live` instance for production code:
+/// ```swift
+/// let client = LightningNodeClient.live
+/// try await client.start()
+/// ```
+///
+/// For testing, use the `mock` instance:
+/// ```swift
+/// let client = LightningNodeClient.mock
+/// ```
 struct LightningNodeClient {
     let start: () async throws -> Void
     let stop: () throws -> Void
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 740f939 and 48a0a97.

📒 Files selected for processing (1)
  • LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (1 hunks)

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

🔭 Outside diff range comments (1)
LDKNodeMonday/View/Home/OnboardingView.swift (1)

Update NetworkSettingsView and ImportWalletView to use @ObservedObject

Both views should use @ObservedObject var viewModel: OnboardingViewModel instead of @EnvironmentObject to maintain consistency with:

  • The parent OnboardingView
  • Other views in the codebase that use @ObservedObject for their view models
🔗 Analysis chain

Line range hint 38-39: Consider updating child view implementations for consistency.

The NetworkSettingsView and ImportWalletView are using the ViewModel as an environment object. Consider passing the required dependencies explicitly to maintain consistency with the new dependency injection pattern.

Let's check if these views have been updated in other files:

Also applies to: 64-65

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if NetworkSettingsView and ImportWalletView have been updated
# to use the new dependency injection pattern

# Search for NetworkSettingsView implementation
echo "Checking NetworkSettingsView implementation:"
rg -A 5 "struct NetworkSettingsView"

# Search for ImportWalletView implementation
echo "Checking ImportWalletView implementation:"
rg -A 5 "struct ImportWalletView"

Length of output: 1255


Script:

#!/bin/bash
# Search for other view implementations to understand the new DI pattern
echo "Checking view implementations in the Home directory:"
rg -B 2 -A 3 "struct \w+View: View" "LDKNodeMonday/View/Home/"

echo "\nChecking OnboardingView specifically:"
rg -B 2 -A 5 "struct OnboardingView" "LDKNodeMonday/View/Home/"

Length of output: 8297

🧹 Nitpick comments (34)
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (2)

89-90: Consider extracting preview constants and validating node ID.

While the addition of lightningClient: .mock is a good practice for preview testing, consider:

  1. Moving the node ID to a preview-specific constant
  2. Validating the node ID string at compile-time
+ private extension PeerDetailsView {
+     static let previewNodeId = "03e39c737a691931dac0f9f9ee803f2ab08f7fd3bbb25ec08d9b8fdb8f51d3a8db"
+ }

  #Preview {
      PeerDetailsView(
          viewModel: .init(
-             nodeId: "03e39c737a691931dac0f9f9ee803f2ab08f7fd3bbb25ec08d9b8fdb8f51d3a8db",
+             nodeId: PeerDetailsView.previewNodeId,
              lightningClient: .mock
          )
      )
  }

89-90: Great architectural improvement!

The addition of lightningClient parameter is a positive change that:

  • Moves away from singleton pattern
  • Improves testability through dependency injection
  • Enables better preview functionality with mock client
LDKNodeMonday/View/Home/Receive/ReceiveView.swift (1)

Line range hint 146-152: Update preview to reflect new dependencies.

The preview section should be updated to include the required lightningClient. This will help maintain the preview's functionality and serve as documentation for other developers.

 #if DEBUG
     #Preview {
-        AmountEntryView(
-            amount: .constant("21")
-        )
+        ReceiveView(
+            lightningClient: .mock() // Assuming there's a mock implementation
+        )
     }
 #endif
LDKNodeMonday/View Model/Home/Receive/JITInvoiceViewModel.swift (1)

57-57: Consider enhancing the color retrieval method.

While the implementation works, consider these improvements:

  1. Use async/await pattern for consistency with other methods
  2. Rename to something more descriptive like updateNetworkColor()

Here's a suggested implementation:

-    func getColor() {
-        let color = lightningClient.getNetworkColor()
+    func updateNetworkColor() async {
+        let color = await lightningClient.getNetworkColor()
         DispatchQueue.main.async {
             self.networkColor = color
         }
     }
LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift (1)

26-28: Consider modernizing to async/await pattern.

While the implementation is correct, this network operation would benefit from using Swift's modern concurrency pattern. This would make the asynchronous nature of the operation more explicit and eliminate the need for manual dispatch queue management in the error handling.

Example refactor:

-    func close() {
+    @MainActor
+    func close() async throws {
-        do {
-            try lightningClient.closeChannel(
-                self.channel.userChannelId,
-                self.channel.counterpartyNodeId
-            )
-            channelDetailViewError = nil
-        } catch let error as NodeError {
-            let errorString = handleNodeError(error)
-            DispatchQueue.main.async {
-                self.channelDetailViewError = .init(
-                    title: errorString.title,
-                    detail: errorString.detail
-                )
-            }
-        } catch {
-            DispatchQueue.main.async {
-                self.channelDetailViewError = .init(
-                    title: "Unexpected error",
-                    detail: error.localizedDescription
-                )
-            }
-        }
+        do {
+            try await lightningClient.closeChannel(
+                self.channel.userChannelId,
+                self.channel.counterpartyNodeId
+            )
+            channelDetailViewError = nil
+        } catch let error as NodeError {
+            let errorString = handleNodeError(error)
+            channelDetailViewError = .init(
+                title: errorString.title,
+                detail: errorString.detail
+            )
+        } catch {
+            channelDetailViewError = .init(
+                title: "Unexpected error",
+                detail: error.localizedDescription
+            )
+        }
     }
LDKNodeMonday/View Model/Home/Receive/BIP21ViewModel.swift (2)

21-23: Add documentation for the initializer.

Consider adding documentation to explain the parameter requirements and any specific initialization behavior.

+    /// Initializes a new BIP21ViewModel instance.
+    /// - Parameter lightningClient: The client used for lightning network operations.
     init(lightningClient: LightningNodeClient) {
         self.lightningClient = lightningClient
     }

27-30: Consider adding input validation for the receive parameters.

While the implementation correctly uses the injected client, consider adding validation for the input parameters before making the client call. For example:

  • Validate that amountSat is greater than 0
  • Ensure message is not empty
  • Verify expirySecs is within a reasonable range
     func receivePayment(amountSat: UInt64, message: String, expirySecs: UInt32) async {
+        guard amountSat > 0 else {
+            DispatchQueue.main.async {
+                self.receiveViewError = .init(
+                    title: "Invalid amount",
+                    detail: "Amount must be greater than 0"
+                )
+            }
+            return
+        }
+        guard !message.isEmpty else {
+            DispatchQueue.main.async {
+                self.receiveViewError = .init(
+                    title: "Invalid message",
+                    detail: "Message cannot be empty"
+                )
+            }
+            return
+        }
         do {
             let unified = try await lightningClient.receive(

Also applies to: 52-52

LDKNodeMonday/View Model/Home/Send/AmountViewModel.swift (3)

18-22: Great architectural improvement using dependency injection!

The introduction of lightningClient as an injected dependency improves testability and reduces coupling by moving away from the singleton pattern (LightningNodeService.shared).


50-54: Consider Swift naming conventions and access level.

While the implementation is correct, consider these improvements:

  1. Rename getColor() to updateNetworkColor() to follow Swift naming conventions
  2. Mark the method as private since it appears to be used internally
-    func getColor() {
+    private func updateNetworkColor() {
         let color = lightningClient.getNetworkColor()
         DispatchQueue.main.async {
             self.networkColor = color
         }
     }

Line range hint 13-15: Consider protocol-oriented design for better testability.

Consider extracting the view model's interface into a protocol. This would further improve testability by allowing easy creation of mock implementations for testing.

protocol AmountViewModelProtocol {
    var networkColor: Color { get }
    var amountConfirmationViewError: MondayError? { get set }
    func send(uriStr: String) async throws -> QrPaymentResult
    func updateNetworkColor()
}

@MainActor
@Observable
class AmountViewModel: AmountViewModelProtocol {
    // ... existing implementation ...
}
LDKNodeMonday/View/Home/Payments/PaymentsView.swift (1)

55-55: Consider adding multiple preview scenarios.

While using the mock client is good practice, consider adding multiple preview scenarios to test different states:

  • Empty payments list
  • List with various payment types
  • Error states

Example implementation:

#if DEBUG
    #Preview("Empty State") {
        PaymentsView(viewModel: .init(lightningClient: .mockEmpty))
    }
    
    #Preview("With Payments") {
        PaymentsView(viewModel: .init(lightningClient: .mockWithPayments))
    }
    
    #Preview("Error State") {
        PaymentsView(viewModel: .init(lightningClient: .mockWithError))
    }
#endif
LDKNodeMonday/View/Home/BitcoinView.swift (1)

Line range hint 293-336: Consider extracting repeated refresh logic.

The same refresh logic appears multiple times in sheet dismissal handlers. Consider extracting it into a method on the view model:

+ extension BitcoinViewModel {
+     func refreshAllBalances() async {
+         await getTotalOnchainBalanceSats()
+         await getTotalLightningBalanceSats()
+         await getPrices()
+         await getSpendableOnchainBalanceSats()
+         await getStatus()
+     }
+ }

Then use it in all locations:

- Task {
-     await viewModel.getTotalOnchainBalanceSats()
-     await viewModel.getTotalLightningBalanceSats()
-     await viewModel.getPrices()
-     await viewModel.getSpendableOnchainBalanceSats()
-     await viewModel.getStatus()
- }
+ Task {
+     await viewModel.refreshAllBalances()
+ }
LDKNodeMonday/View Model/Profile/Danger/SeedViewModel.swift (1)

Line range hint 1-36: Consider adding security-related documentation.

Since this view model handles sensitive seed phrase data, consider adding class-level documentation explaining:

  • Security considerations
  • Proper usage guidelines
  • Warning about handling seed phrases

Example addition:

+ /// SeedViewModel: Handles the secure retrieval and display of wallet recovery phrases.
+ /// - Warning: This class handles sensitive cryptographic material. Ensure all UI interactions
+ ///           are protected and seed phrases are never logged or stored in plain text.
 class SeedViewModel: ObservableObject {
LDKNodeMonday/View/Settings/Danger/SeedView.swift (1)

Line range hint 1-101: Consider additional security measures for sensitive data display.

While the current implementation includes good security practices, consider these enhancements:

  1. Add blur protection when app enters background
  2. Add screenshot prevention/warning
  3. Make clipboard clear duration configurable

Example implementation:

// Add to view modifier chain
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
    // Auto-hide seed phrase when app goes to background
    if showRecoveryPhrase {
        showRecoveryPhrase = false
    }
}
.screenshotProhibited() // iOS 17+ only
LDKNodeMonday/View Model/Profile/Channel/ChannelsListViewModel.swift (1)

32-41: Consider improving error handling and type safety.

A few suggestions to enhance the implementation:

  1. Replace try? with proper error handling to avoid silently ignoring network fetch errors
  2. Use type-safe network comparison instead of string comparison
  3. Expand the comment to explain why mainnet-only alias fetching is temporary

Consider this improvement:

-        if let networkString = try? keyClient.getNetwork(),
-            networkString == Network.bitcoin.description
+        do {
+            let network = try await keyClient.getNetwork()
+            // Only fetch aliases on mainnet due to LDK Node limitation
+            // See: https://github.com/lightningdevkit/ldk-node/issues/234
+            guard network == Network.bitcoin else { return }
+            for channel in channels {
+                await fetchAlias(for: channel.counterpartyNodeId)
+            }
+        } catch {
+            self.channelsListViewError = .init(
+                title: "Network Error",
+                detail: "Failed to determine network: \(error.localizedDescription)"
+            )
+        }
LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (2)

85-91: Consider extracting magic numbers into constants.

The circle dimensions and icon sizes could be defined as constants for better maintainability.

+ private enum Constants {
+     static let circleSize: CGFloat = 40
+     static let iconSize: CGFloat = 16
+ }
+
  ZStack {
      Circle()
          .stroke(lineWidth: 2)
-         .frame(width: 40, height: 40)
+         .frame(width: Constants.circleSize, height: Constants.circleSize)
      Image(systemName: "fibrechannel")
          .resizable()
          .scaledToFit()
-         .frame(width: 16, height: 16)
+         .frame(width: Constants.iconSize, height: Constants.iconSize)
  }

111-114: Consider improving numerical value formatting.

The msat to sat conversion and numerical formatting could be improved:

  1. Extract the conversion logic to computed properties
  2. Add proper number formatting for better accessibility
+ private var formattedOutboundSats: String {
+     let sats = channel.outboundCapacityMsat/1000
+     return NumberFormatter.localizedString(from: NSNumber(value: sats), number: .decimal)
+ }
+
+ private var formattedInboundSats: String {
+     let sats = channel.inboundCapacityMsat/1000
+     return NumberFormatter.localizedString(from: NSNumber(value: sats), number: .decimal)
+ }
+
  HStack {
-     Text("Send \(channel.outboundCapacityMsat/1000) sats")
+     Text("Send \(formattedOutboundSats) sats")
      Spacer()
-     Text("Receive \(channel.inboundCapacityMsat/1000) sats")
+     Text("Receive \(formattedInboundSats) sats")
  }
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (4)

40-42: Consider adding error handling for peer listing.

The onAppear handler should handle potential errors when listing peers. Consider showing an error state to improve user experience.

 .onAppear {
-    viewModel.listPeers()
+    Task {
+        do {
+            await viewModel.listPeers()
+        } catch {
+            // Handle error state
+        }
+    }
 }

67-68: Remove duplicate list style.

The .listStyle(.plain) modifier is already applied in the parent view, making this redundant.


76-85: Consider extracting magic numbers into constants.

The hard-coded dimensions and spacing values should be extracted into named constants for better maintainability.

+private enum Constants {
+    static let avatarSize: CGFloat = 40
+    static let iconSize: CGFloat = 16
+    static let horizontalSpacing: CGFloat = 15
+}

-HStack(alignment: .center, spacing: 15) {
+HStack(alignment: .center, spacing: Constants.horizontalSpacing) {
     ZStack {
         Circle()
             .stroke(lineWidth: 2)
-            .frame(width: 40, height: 40)
+            .frame(width: Constants.avatarSize, height: Constants.avatarSize)
         Image(systemName: "person.line.dotted.person")
             .resizable()
             .scaledToFit()
-            .frame(width: 16, height: 16)
+            .frame(width: Constants.iconSize, height: Constants.iconSize)
     }

98-117: Reduce code duplication in connection status styling.

The font and color modifiers are duplicated between the connected and disconnected states. Consider extracting the common styling.

 private struct ConnectionStatus: View {
     let isConnected: Bool
+    
+    private var statusText: String { isConnected ? "Connected" : "Not Connected" }
+    private var statusIcon: String { isConnected ? "checkmark" : "xmark" }
 
     var body: some View {
-        if isConnected {
-            HStack(alignment: .firstTextBaseline, spacing: 2) {
-                Text("Connected")
-                Image(systemName: "checkmark")
-            }
-            .font(.caption)
-            .foregroundColor(.secondary)
-        } else {
-            HStack {
-                Text("Not Connected")
-                Image(systemName: "xmark")
-            }
-            .font(.caption)
-            .foregroundColor(.secondary)
-        }
+        HStack(alignment: .firstTextBaseline, spacing: 2) {
+            Text(statusText)
+            Image(systemName: statusIcon)
+        }
+        .font(.caption)
+        .foregroundColor(.secondary)
     }
 }
LDKNodeMonday/View Model/Profile/Peer/DisconnectViewModel.swift (1)

16-21: Add documentation for the initializer parameters.

Consider adding a documentation comment to explain the purpose and requirements of each parameter, especially since this is a public initializer.

+    /// Initializes a new DisconnectViewModel
+    /// - Parameters:
+    ///   - nodeId: The public key of the peer to disconnect
+    ///   - lightningClient: The client used to perform lightning node operations
     init(
         nodeId: PublicKey,
         lightningClient: LightningNodeClient
     ) {
LDKNodeMonday/View/Settings/Peers/PeerView.swift (2)

Line range hint 33-65: Consider enhancing input validation and feedback.

The current implementation could benefit from more robust input validation:

  1. Add real-time validation feedback for node ID and address formats
  2. Consider using a dedicated input validation service
  3. Show validation state in the UI (e.g., green checkmark for valid input)

Example enhancement for the node ID field:

 TextField(
     "03a5b467d7f...4c2b099b8250c",
     text: $viewModel.nodeId
 )
+.onChange(of: viewModel.nodeId) { _, newValue in
+    viewModel.validateNodeId(newValue)
+}
+.overlay(
+    HStack {
+        Spacer()
+        if viewModel.isValidNodeId {
+            Image(systemName: "checkmark.circle.fill")
+                .foregroundColor(.green)
+        }
+    }.padding(.trailing)
+)

Line range hint 142-157: Consider structuring error handling with an enum.

The current error handling uses a custom error type with title and detail. Consider using a structured enum for better type safety and maintainability.

Example implementation:

enum PeerViewError: LocalizedError {
    case invalidPaste
    case invalidQRCode
    case scanError(String)
    
    var errorDescription: String {
        switch self {
        case .invalidPaste:
            return "Paste Parsing Error"
        case .invalidQRCode:
            return "QR Parsing Error"
        case .scanError:
            return "Scan Error"
        }
    }
    
    var recoverySuggestion: String {
        switch self {
        case .invalidPaste:
            return "Failed to parse the Pasteboard."
        case .invalidQRCode:
            return "Failed to parse the QR code."
        case .scanError(let message):
            return message
        }
    }
}
LDKNodeMonday/View Model/Profile/Peer/PeersListViewModel.swift (1)

13-13: LGTM! Good use of dependency injection.

The shift from using a shared service to dependency injection via LightningNodeClient improves testability and modularity.

This architectural change:

  • Makes dependencies explicit
  • Enables better testing through mock clients
  • Reduces coupling with global state

Also applies to: 15-16

LDKNodeMonday/View Model/Profile/Channel/ChannelAddViewModel.swift (1)

43-49: Document the purpose of the hardcoded boolean parameter.

The false parameter passed to connectOpenChannel lacks context. Consider:

  1. Adding a named parameter or documentation explaining its purpose
  2. Using a constant with a descriptive name if this is a configuration value
-            false
+            shouldWaitForScid: false  // Add parameter name for clarity
LDKNodeMonday/View Model/Home/OnboardingViewModel.swift (1)

27-30: Consider refactoring repeated save operations

The calls to keyClient.saveNetwork and keyClient.saveEsploraURL are repeated in multiple places (selectedNetwork didSet, selectedEsploraServer didSet, and saveSeed() function). Refactoring these into a separate method could reduce code duplication and improve maintainability.

You might extract these repeated save operations into a dedicated method, such as:

private func saveNetworkSettings() throws {
    try keyClient.saveNetwork(selectedNetwork.description)
    try keyClient.saveEsploraURL(selectedEsploraServer.url)
}

Then, update the places where these calls occur:

// In selectedNetwork didSet
- try keyClient.saveNetwork(networkString)
- try keyClient.saveEsploraURL(selectedEsploraServer.url)
+ try saveNetworkSettings()

// In selectedEsploraServer didSet
- try keyClient.saveEsploraURL(selectedEsploraServer.url)
+ try saveNetworkSettings()

// In saveSeed() function
- try keyClient.saveNetwork(selectedNetwork.description)
- try keyClient.saveEsploraURL(selectedEsploraServer.url)
+ try saveNetworkSettings()

Also applies to: 45-45, 114-116

LDKNodeMonday/App/LDKNodeMondayApp.swift (1)

82-82: Use lightningClient instead of LightningNodeClient.live in applicationWillTerminate

To maintain consistency with dependency injection and ensure that the same instance of lightningClient is used throughout the application lifecycle, consider using lightningClient.stop() rather than directly calling LightningNodeClient.live.stop().

Apply this diff to make the change:

-        try? LightningNodeClient.live.stop()
+        try? lightningClient.stop()

This change ensures that if the lightningClient has been mocked or altered for testing purposes, the correct instance is stopped upon application termination.

LDKNodeMonday/View Model/Home/BitcoinViewModel.swift (1)

31-40: Consider handling edge cases in USD value calculations.

The computed properties should handle potential edge cases:

  • Zero balances
  • Extremely large numbers that might cause overflow
  • Invalid/zero price values
 var satsPrice: String {
+    guard price > 0 else { return "$0.00" }
     let usdValue = Double(totalBalance).valueInUSD(price: price)
     return usdValue
 }

 var totalUSDValue: String {
+    guard price > 0 else { return "$0.00" }
     let totalUSD = Double(totalBalance + totalLightningBalance).valueInUSD(price: price)
     return totalUSD
 }
LDKNodeMonday/View/Settings/SettingsView.swift (1)

38-45: Avoid redundant data fetching in both initializer and onAppear

The viewModel methods getNodeID(), getNetwork(), getEsploraUrl(), and getStatus() are called both in the initializer of SettingsViewModel and within the .onAppear modifier in SettingsView. This results in redundant data fetching and unnecessary network or processing overhead.

Consider removing these calls from either the initializer or the .onAppear block. If the data is required upon view appearance, it's preferable to keep the calls in .onAppear and simplify the initializer:

-    init(
-        appState: Binding<AppState>,
-        keyClient: KeyClient = .live,
-        lightningClient: LightningNodeClient
-    ) {
-        _appState = appState
-        self.keyClient = keyClient
-        self.lightningClient = lightningClient
-        // Call these immediately to populate data
-        getNodeID()
-        getNetwork()
-        getEsploraUrl()
-        Task {
-            await getStatus()
-        }
-    }
+    init(
+        appState: Binding<AppState>,
+        keyClient: KeyClient = .live,
+        lightningClient: LightningNodeClient
+    ) {
+        _appState = appState
+        self.keyClient = keyClient
+        self.lightningClient = lightningClient
+    }
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (2)

34-39: Avoid redundant data fetching in initializer

The initializer calls getNodeID(), getNetwork(), getEsploraUrl(), and getStatus(). Since these methods are also called in the .onAppear block of SettingsView, this leads to redundant data fetching.

Consider removing these calls from the initializer to prevent unnecessary duplicated work:

     init(
         appState: Binding<AppState>,
         keyClient: KeyClient = .live,
         lightningClient: LightningNodeClient
     ) {
         _appState = appState
         self.keyClient = keyClient
         self.lightningClient = lightningClient
-        // Call these immediately to populate data
-        getNodeID()
-        getNetwork()
-        getEsploraUrl()
-        Task {
-            await getStatus()
-        }
     }

43-45: Add error handling to getNodeID()

The getNodeID() function does not handle potential errors that may occur when retrieving the node ID. If lightningClient.nodeId() can fail or throw an error, consider adding error handling to provide user feedback.

     func getNodeID() {
-        let nodeID = lightningClient.nodeId()
-        self.nodeID = nodeID
+        do {
+            let nodeID = try lightningClient.nodeId()
+            self.nodeID = nodeID
+        } catch {
+            DispatchQueue.main.async {
+                self.nodeIDError = .init(title: "Error", detail: error.localizedDescription)
+            }
+        }
     }
LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (2)

274-302: Well-designed client interface!

The LightningNodeClient struct provides a clean, injectable interface that enhances testability. The closure-based design effectively encapsulates the LightningNodeService functionality.

Consider adding documentation comments to describe the purpose of the struct and its role in the architecture. This would help other developers understand the motivation behind this abstraction.

+/// A client interface for interacting with the Lightning Node Service.
+/// This struct provides a testable abstraction layer over `LightningNodeService`,
+/// enabling dependency injection and easier mocking in tests.
 struct LightningNodeClient {

374-422: Enhance mock implementation for better testing.

The mock implementation provides good test data, but consider these improvements:

  1. Make mock values configurable to support different test scenarios
  2. Use more realistic test data for node ID and addresses

Example of making values configurable:

 extension LightningNodeClient {
+    struct MockConfig {
+        var nodeId: String
+        var spendableBalance: UInt64
+        // ... other configurable values
+        
+        static let standard = MockConfig(
+            nodeId: "038474837483784378437843784378437843784378",
+            spendableBalance: 100_000
+        )
+    }
+    
     static let mock = Self(
         start: {},
         stop: {},
-        nodeId: { "038474837483784378437843784378437843784378" },
+        nodeId: { MockConfig.standard.nodeId },
         // ... configure other values similarly
     )
+    
+    static func mock(config: MockConfig) -> Self {
+        Self(
+            start: {},
+            stop: {},
+            nodeId: { config.nodeId },
+            // ... use config values
+        )
+    }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 48a0a97 and 83c2b5c.

📒 Files selected for processing (31)
  • LDKNodeMonday/App/LDKNodeMondayApp.swift (4 hunks)
  • LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (1 hunks)
  • LDKNodeMonday/View Model/Home/BitcoinViewModel.swift (2 hunks)
  • LDKNodeMonday/View Model/Home/OnboardingViewModel.swift (6 hunks)
  • LDKNodeMonday/View Model/Home/Payments/PaymentsViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Home/Receive/BIP21ViewModel.swift (2 hunks)
  • LDKNodeMonday/View Model/Home/Receive/JITInvoiceViewModel.swift (2 hunks)
  • LDKNodeMonday/View Model/Home/Send/AmountViewModel.swift (2 hunks)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelAddViewModel.swift (3 hunks)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelsListViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/Danger/SeedViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/Peer/DisconnectViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/Peer/PeersListViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (3 hunks)
  • LDKNodeMonday/View/Home/BitcoinView.swift (5 hunks)
  • LDKNodeMonday/View/Home/OnboardingView.swift (1 hunks)
  • LDKNodeMonday/View/Home/Payments/PaymentsView.swift (1 hunks)
  • LDKNodeMonday/View/Home/Receive/BIP21View.swift (1 hunks)
  • LDKNodeMonday/View/Home/Receive/JITInvoiceView.swift (1 hunks)
  • LDKNodeMonday/View/Home/Receive/ReceiveView.swift (2 hunks)
  • LDKNodeMonday/View/Home/Send/AmountView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (3 hunks)
  • LDKNodeMonday/View/Settings/Danger/SeedView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift
  • LDKNodeMonday/View/Home/Receive/BIP21View.swift
  • LDKNodeMonday/View/Home/Send/AmountView.swift
  • LDKNodeMonday/View/Home/Receive/JITInvoiceView.swift
🔇 Additional comments (53)
LDKNodeMonday/View/Home/Receive/ReceiveView.swift (3)

12-12: LGTM! Good use of dependency injection.

The immutable lightningClient property ensures proper initialization and dependency management.


35-35: LGTM! Proper dependency injection in view model initialization.

The lightningClient is correctly passed to the JITInvoiceView's view model.


37-37: LGTM! Consistent dependency injection pattern.

The lightningClient is correctly passed to the BIP21View's view model, maintaining consistency with JITInvoiceView.

LDKNodeMonday/View Model/Home/Receive/JITInvoiceViewModel.swift (2)

19-23: Great architectural improvement!

The switch from singleton pattern (LightningNodeService.shared) to dependency injection improves testability and follows SOLID principles. The private access level for lightningClient properly encapsulates the dependency.


32-36: Clean implementation of the client usage!

The update maintains proper error handling while cleanly integrating with the new lightningClient. The async/await pattern and main thread dispatching are handled correctly.

LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift (2)

14-14: LGTM! Well-structured property declaration.

The property is correctly declared as private and immutable, following Swift best practices for dependency injection.


16-21: LGTM! Clean initializer implementation.

The initializer follows a good pattern for dependency injection and maintains clean formatting with parameters on separate lines.

LDKNodeMonday/View Model/Home/Receive/BIP21ViewModel.swift (1)

19-19: LGTM! Good use of immutability and encapsulation.

The property is correctly declared as private and immutable, ensuring thread safety and proper encapsulation.

LDKNodeMonday/View Model/Home/Send/AmountViewModel.swift (1)

26-26: LGTM! Consistent with the new architecture.

The change properly utilizes the injected client while maintaining robust error handling.

LDKNodeMonday/View Model/Home/Payments/PaymentsViewModel.swift (3)

14-14: LGTM! Good encapsulation.

The private property ensures proper encapsulation of the lightning client dependency.


16-18: LGTM! Good use of dependency injection.

The initializer properly implements dependency injection, making the code more testable and flexible.


20-22: LGTM! Clean implementation.

The listPayments method cleanly delegates to the injected client, maintaining single responsibility.

LDKNodeMonday/View/Home/BitcoinView.swift (5)

242-247: LGTM! Clean dependency injection implementation.

The addition of lightningClient parameter follows good dependency injection practices.


293-293: LGTM! Proper dependency passing to sheet view.

The lightningClient is correctly passed to the presented sheet view.


308-308: LGTM! Consistent dependency injection pattern.

The lightningClient is properly injected into the PaymentsView's viewModel.


Line range hint 322-328: LGTM! Good data refresh implementation.

The lightningClient is properly injected, and the balance refresh on view disappear ensures data consistency.


355-359: LGTM! Proper preview setup with mock client.

Using .mock for lightningClient in preview follows best practices for SwiftUI previews.

LDKNodeMonday/View Model/Profile/Danger/SeedViewModel.swift (1)

15-19: Great job implementing dependency injection!

Moving away from the singleton pattern to dependency injection improves testability and flexibility.

LDKNodeMonday/View/Settings/Danger/SeedView.swift (1)

101-101: LGTM! Preview updated correctly.

Preview now uses the mock client, maintaining consistency with the ViewModel changes.

LDKNodeMonday/View Model/Profile/Channel/ChannelsListViewModel.swift (2)

15-16: LGTM! Well-structured property declarations.

The new properties follow Swift best practices with appropriate access levels and immutability.


21-28: LGTM! Clean dependency injection implementation.

The initializer is well-structured with:

  • Clear parameter ordering
  • Sensible default value for keyClient
  • Proper property initialization
LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (6)

9-9: LGTM! Import statement is appropriate.

The addition of the LDKNode import aligns with the integration of Lightning Node functionality.


31-34: LGTM! Proper dependency injection.

The lightningClient is correctly passed to the detail view through the view model.


38-41: LGTM! Good modularization.

Extracting the channel presentation logic into a separate ChannelRow view improves code organization and reusability.


58-62: LGTM! Enhanced accessibility.

Good addition of accessibility support with dynamic type sizing and proper navigation styling.


63-74: LGTM! Well-structured navigation.

The toolbar implementation follows SwiftUI best practices and properly passes the lightningClient to the add view.


124-124: LGTM! Proper preview setup.

The preview correctly initializes the view with mock clients for both node info and lightning functionality.

LDKNodeMonday/View/Settings/Peers/PeersListView.swift (3)

20-21: LGTM! Clean separation of concerns.

Good job extracting the peer list logic into a separate component, making the code more maintainable.


23-26: Great accessibility and UI configuration.

Excellent attention to accessibility with dynamic type size support and proper list styling.


46-49: Good use of dependency injection.

Clean implementation with explicit dependencies through parameters rather than global state.

LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1)

159-160: LGTM! Good use of dependency injection with mock client in preview.

The addition of lightningClient: .mock to the preview's view model initialization follows good testing practices by using dependency injection.

However, the AI summary mentions changes to the ChannelDetailViewModel class that are not visible in the provided code. Let's verify these changes:

✅ Verification successful

Verified: Dependency injection and mock client usage are properly implemented

The preview's use of .mock client aligns perfectly with the view model's implementation:

  • ChannelDetailViewModel properly accepts lightningClient through dependency injection
  • The close() method correctly utilizes the injected client
  • Error handling and threading considerations are well implemented
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for ChannelDetailViewModel implementation
rg -A 10 "class ChannelDetailViewModel"

# Verify the view model's usage of lightningClient
ast-grep --pattern 'class ChannelDetailViewModel {
  $$$
  func close() {
    $$$
  }
  $$$
}'

Length of output: 1284


Script:

#!/bin/bash
# Search for close method in ChannelDetailViewModel
rg -A 10 "func close\(\)" "LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift"

Length of output: 510

LDKNodeMonday/View Model/Profile/Peer/DisconnectViewModel.swift (2)

14-14: LGTM! Well-structured property declaration.

The private access level is appropriate for this internal dependency, following good encapsulation principles.


26-26: Verify error handling coverage for LightningNodeClient.

The error handling looks comprehensive, but please verify that all possible error cases from LightningNodeClient.disconnect() are properly handled.

✅ Verification successful

Error handling coverage is appropriate

The implementation properly handles both specific NodeError cases and unexpected errors through the catch-all block. The error propagation chain from LDK through the service layer to the view model is correctly maintained.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for all error types that LightningNodeClient.disconnect might throw
ast-grep --pattern 'func disconnect($$$) throws $error {
  $$$
}'

Length of output: 67


Script:

#!/bin/bash
# Find files containing LightningNodeClient
echo "=== Files containing LightningNodeClient ==="
rg "LightningNodeClient" -l

echo -e "\n=== LightningNodeClient implementation ==="
rg "class LightningNodeClient|protocol LightningNodeClient" -A 10

echo -e "\n=== Searching for disconnect method ==="
rg "func disconnect.*\(" -A 5

Length of output: 2672

LDKNodeMonday/View/Home/OnboardingView.swift (1)

105-105: LGTM! Good use of dependency injection.

The preview modification correctly implements the new dependency injection pattern, improving testability by using the mock client.

LDKNodeMonday/View/Settings/Peers/PeerView.swift (2)

211-211: LGTM! Good use of dependency injection in preview.

The change to use a mock client in the preview is a good practice, making the preview more reliable and independent of the actual Lightning node service.


211-211: Verify view model implementation for proper dependency injection.

The preview changes suggest that PeerViewModel has been updated to use dependency injection with LightningNodeClient. Let's verify the implementation:

✅ Verification successful

✅ Dependency injection properly implemented

The PeerViewModel correctly implements dependency injection:

  • Declares lightningClient as a required dependency
  • Uses the injected client throughout its implementation
  • Preview correctly uses mock client
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for PeerViewModel implementation
rg -l "class PeerViewModel" 

# Check if connect method uses lightningClient instead of shared service
ast-grep --pattern 'class PeerViewModel {
  $$$
  func connect($$$) {
    $$$
  }
  $$$
}'

Length of output: 180


Script:

#!/bin/bash
# Check class initialization and stored property
ast-grep --pattern 'class PeerViewModel {
  let lightningClient: $_
  $$$
}'

# Check for any remaining usage of shared instance
rg -A 3 "LightningNodeClient\.shared" "LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift"

# View the full implementation for thorough analysis
cat "LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift"

Length of output: 1578

LDKNodeMonday/View Model/Profile/Peer/PeersListViewModel.swift (1)

19-21: Verify error handling for Lightning Network operations.

The listPeers() implementation appears to assume the operation always succeeds. Lightning Network operations can fail due to various reasons (node offline, network issues, etc.).

Let's check if error handling exists in the client implementation:

Consider adding error handling if not already present in the client layer:

func listPeers() {
    do {
        self.peers = try lightningClient.listPeers()
    } catch {
        // Handle error appropriately
        self.peers = []
        // Consider adding error state handling
    }
}
LDKNodeMonday/View Model/Profile/Channel/ChannelAddViewModel.swift (2)

18-19: LGTM! Good use of dependency injection.

The addition of the private lightningClient property improves testability and follows good architectural principles by removing direct dependency on shared services.


29-31: Verify all instantiations of ChannelAddViewModel.

The initializer change requires all existing instantiations of ChannelAddViewModel to be updated with a LightningNodeClient instance.

✅ Verification successful

All ChannelAddViewModel instantiations are properly updated

The initializer changes have been correctly implemented across the codebase:

  • Production usage in ChannelsListView properly initializes with lightningClient
  • Preview code correctly uses the mock client
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for ChannelAddViewModel instantiations to ensure they've been updated
rg -l "ChannelAddViewModel\(" | xargs rg "ChannelAddViewModel\([^)]*\)"

Length of output: 73


Script:

#!/bin/bash
# First, find all files containing ChannelAddViewModel
echo "=== Files containing ChannelAddViewModel ==="
rg --type swift "ChannelAddViewModel" -l

echo -e "\n=== Usages of ChannelAddViewModel with context ==="
rg --type swift -B 2 -A 2 "ChannelAddViewModel"

Length of output: 1796


Script:

#!/bin/bash
# Get the full content of ChannelAddView.swift to find initialization
echo "=== Full content of ChannelAddView.swift ==="
cat "LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift"

Length of output: 9371


Script:

#!/bin/bash
# Search for files that create ChannelAddView
echo "=== Files containing ChannelAddView creation ==="
rg -B 3 -A 3 "ChannelAddView\(" --type swift

Length of output: 1303

LDKNodeMonday/View Model/Home/OnboardingViewModel.swift (4)

13-14: Implementing dependency injection for lightningClient and keyClient

Introducing lightningClient and keyClient as private properties and injecting them via the initializer enhances modularity and testability by avoiding reliance on singleton instances.


82-89: Updating initializer for dependency injection

The updated initializer now accepts lightningClient and keyClient as parameters, promoting dependency injection and enhancing testability by allowing the injection of mock clients during testing.


92-95: Proper error handling when retrieving stored settings

Using keyClient.getNetwork() and keyClient.getEsploraURL() with proper error handling ensures that the application gracefully handles missing or corrupted stored data.


139-139: Consistent use of lightningClient to retrieve network color

Using lightningClient.getNetworkColor() maintains consistency with the dependency injection approach and removes reliance on singleton patterns.

LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift (2)

17-22: Implementing dependency injection for lightningClient

Adding lightningClient as a private property and injecting it via the initializer enhances modularity and testability by avoiding dependency on a singleton instance.


28-31: Using lightningClient in the connect method

Switching to lightningClient.connect() aligns with the dependency injection pattern and ensures that the PeerViewModel is decoupled from global instances, improving testability.

LDKNodeMonday/App/LDKNodeMondayApp.swift (4)

15-15: Initializing lightningClient as a private property

Introducing lightningClient as a private property allows for centralized management of the Lightning Node Client within the app and facilitates dependency injection into view models.


25-27: Passing lightningClient to OnboardingViewModel

Injecting lightningClient into OnboardingViewModel promotes dependency injection, enhancing modularity and allowing for easier testing and maintenance.


30-34: Passing lightningClient to BitcoinViewModel

Injecting lightningClient into BitcoinViewModel ensures consistency in how dependencies are provided throughout the app, improving testability and modularity.


60-61: Using lightningClient to start and listen for events

Replacing LightningNodeService.shared with lightningClient in the start() function adheres to the dependency injection pattern and eliminates reliance on singleton instances.

LDKNodeMonday/View Model/Home/BitcoinViewModel.swift (2)

26-30: Clean dependency injection implementation!

The lightningClient property properly introduces dependency injection, improving testability and modularity.


Line range hint 52-111: Methods correctly updated to use lightningClient.

All service method calls have been properly migrated to use the injected lightningClient, maintaining the existing asynchronous patterns and error handling.

LDKNodeMonday/View/Settings/SettingsView.swift (1)

22-58: Refactored SettingsView improves modularity and readability

The refactoring of SettingsView to utilize SettingsFormView and dedicated subsections (WalletSection, LightningNodeSection, DangerZoneSection) enhances the modularity and maintainability of the codebase. Breaking down the settings into smaller, reusable components improves readability and promotes better organization.

LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (1)

329-338: Parameter mismatch fixed.

The announceChannel parameter is now correctly passed to the service method.

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 (2)
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (1)

21-39: Consider deferring async initialization

While dependency injection of lightningClient is good for testability, calling async methods directly in init could lead to race conditions. Consider moving the initialization logic to a separate async setup method.

 init(
     appState: Binding<AppState>,
     keyClient: KeyClient = .live,
     lightningClient: LightningNodeClient
 ) {
     _appState = appState
     self.keyClient = keyClient
     self.lightningClient = lightningClient
-    // Call these immediately to populate data, wasnt immediately doing it otherwise?
-    getNodeID()
-    getNetwork()
-    getEsploraUrl()
-    Task {
-        await getStatus()
-    }
 }
+
+func setup() async {
+    getNodeID()
+    getNetwork()
+    getEsploraUrl()
+    await getStatus()
+}
LDKNodeMonday/View/Settings/SettingsView.swift (1)

148-177: Consider enhancing copy feedback UX

The current implementation has a hard-coded 2-second delay for the checkmark. Consider:

  1. Using haptic feedback for better user experience
  2. Making the duration configurable
 Button {
     UIPasteboard.general.string = viewModel.nodeID
     showCheckmark = true
+    UINotificationFeedbackGenerator().notificationOccurred(.success)
     DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
         showCheckmark = false
     }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 83c2b5c and c325a08.

📒 Files selected for processing (2)
  • LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (3 hunks)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
🔇 Additional comments (5)
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (3)

Line range hint 43-61: LGTM! Good error handling pattern

The error handling pattern is well-implemented, properly distinguishing between NodeError and other error types.


Line range hint 66-91: Improve error handling in delete method

The error handling could be improved by:

  1. Making the method async to properly handle asynchronous operations
  2. Adding specific error handling for deleteNetwork and deleteEsplora operations

This issue was previously identified in a past review. Please refer to the existing suggestion for the implementation details.


128-134: Verify async requirement for getStatus

The method is marked as async but lightningClient.status() appears to be synchronous. If status() is indeed synchronous, this method doesn't need to be async.

This issue was previously identified in a past review. To verify the async requirement, let's check the implementation:

#!/bin/bash
# Search for the status method implementation in LightningNodeClient
ast-grep --pattern 'func status() { $$$' 
LDKNodeMonday/View/Settings/SettingsView.swift (2)

22-58: LGTM! Good view modularization

Breaking down the view into smaller components improves maintainability and readability.


224-224: LGTM! Good preview setup

Using the mock client for previews is a good practice for SwiftUI development.

Comment on lines +179 to +218
private struct DangerZoneSection: View {
@ObservedObject var viewModel: SettingsViewModel
@Binding var showStopNodeConfirmation: Bool
@Binding var showDeleteSeedConfirmation: Bool
let dismiss: DismissAction

var body: some View {
Section {
Button {
showStopNodeConfirmation = true
} label: {
Text("Stop Node")
}
.foregroundColor(.red)
.alert("Warning!", isPresented: $showStopNodeConfirmation) {
Button("Yes", role: .destructive) { viewModel.stop() }
Button("No", role: .cancel) {}
} message: {
Text("Are you sure you want to stop the node?")
}

Button {
showDeleteSeedConfirmation = true
} label: {
Text("Delete Wallet")
}
.foregroundColor(.red)
.alert("Warning!", isPresented: $showDeleteSeedConfirmation) {
Button("Yes", role: .destructive) {
viewModel.delete()
dismiss()
}
Button("No", role: .cancel) {}
} message: {
Text("All funds will be lost.\nAre you sure you want to delete the wallet?")
}
} header: {
Text("Danger Zone").foregroundColor(.primary)
}
.foregroundColor(.primary)
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

Add loading states to prevent multiple operations

The dangerous operations (stop node, delete wallet) should disable buttons during execution to prevent multiple triggers.

 struct DangerZoneSection: View {
     @ObservedObject var viewModel: SettingsViewModel
     @Binding var showStopNodeConfirmation: Bool
     @Binding var showDeleteSeedConfirmation: Bool
+    @State private var isProcessing = false
     let dismiss: DismissAction

     var body: some View {
         Section {
             Button {
                 showStopNodeConfirmation = true
             } label: {
                 Text("Stop Node")
             }
             .foregroundColor(.red)
+            .disabled(isProcessing)
             .alert("Warning!", isPresented: $showStopNodeConfirmation) {
-                Button("Yes", role: .destructive) { viewModel.stop() }
+                Button("Yes", role: .destructive) {
+                    isProcessing = true
+                    viewModel.stop()
+                    isProcessing = false
+                }
                 Button("No", role: .cancel) {}
             }

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

@reez reez changed the title (draft) chore: lightningnodeclient chore: lightningnodeclient Jan 17, 2025
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

🔭 Outside diff range comments (1)
LDKNodeMonday.xcodeproj/project.pbxproj (1)

Line range hint 1037-1041: Remove duplicate LDKNode package dependencies.

There are multiple entries for the LDKNode package dependency. This could lead to confusion and potential versioning conflicts.

Keep only the first entry with the exact version requirement and remove the duplicate entries:

-		AE060C372C051B59006724F1 /* LDKNode */ = {
-			isa = XCSwiftPackageProductDependency;
-			productName = LDKNode;
-		};
-		AE80C2042C4AB5E4006E7193 /* LDKNode */ = {
-			isa = XCSwiftPackageProductDependency;
-			productName = LDKNode;
-		};

Also applies to: 1042-1046, 1047-1051

🧹 Nitpick comments (4)
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (4)

33-39: Consider deferring immediate data population.

The initializer makes multiple synchronous and one asynchronous call immediately, with a comment suggesting data population issues. This could lead to performance impacts during view model creation.

Consider introducing a separate setup() method:

     init(
         appState: Binding<AppState>,
         keyClient: KeyClient = .live,
         lightningClient: LightningNodeClient
     ) {
         _appState = appState
         self.keyClient = keyClient
         self.lightningClient = lightningClient
-        // Call these immediately to populate data, wasnt immediately doing it otherwise?
-        getNodeID()
-        getNetwork()
-        getEsploraUrl()
-        Task {
-            await getStatus()
-        }
+        setup()
     }
+    
+    private func setup() {
+        Task {
+            // Populate initial data
+            getNodeID()
+            getNetwork()
+            getEsploraUrl()
+            await getStatus()
+        }
+    }

21-21: Add documentation for the lightning client property.

Add a documentation comment explaining the purpose and lifecycle of the lightningClient property.

+    /// Client for interacting with the Lightning node. This instance is shared across the app
+    /// to maintain a single connection to the node.
     let lightningClient: LightningNodeClient

Line range hint 94-118: Reduce error handling duplication.

The error handling pattern is duplicated across multiple methods. Consider extracting it into a reusable function.

+    private func handleError(_ operation: () throws -> Void) {
+        do {
+            try operation()
+        } catch let error as NodeError {
+            let errorString = handleNodeError(error)
+            DispatchQueue.main.async {
+                self.nodeIDError = .init(title: errorString.title, detail: errorString.detail)
+            }
+        } catch {
+            DispatchQueue.main.async {
+                self.nodeIDError = .init(
+                    title: "Unexpected error",
+                    detail: error.localizedDescription
+                )
+            }
+        }
+    }

     func getNetwork() {
-        do {
+        handleError {
             let network = try keyClient.getNetwork()
             DispatchQueue.main.async {
                 self.network = network
             }
-        } catch let error as NodeError {
-            let errorString = handleNodeError(error)
-            DispatchQueue.main.async {
-                self.nodeIDError = .init(title: errorString.title, detail: errorString.detail)
-            }
-        } catch {
-            DispatchQueue.main.async {
-                self.nodeIDError = .init(
-                    title: "Unexpected error",
-                    detail: error.localizedDescription
-                )
-            }
         }
     }

134-141: Remove debug print statements.

Debug print statements should be removed before merging to production.

     func getStatus() async {
         let status = lightningClient.status()
         await MainActor.run {
-            print("SettingsViewModel - Setting status on main thread")
             self.status = status
             self.isStatusFinished = true
-            print("SettingsViewModel - Status set: \(String(describing: self.status))")
         }
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c325a08 and cc386c9.

📒 Files selected for processing (3)
  • LDKNodeMonday.xcodeproj/project.pbxproj (2 hunks)
  • LDKNodeMonday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (2 hunks)
  • LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (5 hunks)
🔇 Additional comments (6)
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (1)

134-141: Ensure correct asynchronous handling in getStatus()

The function is marked as async but doesn't contain any awaitable operations except for the MainActor.run.

LDKNodeMonday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (3)

18-19: Verify compatibility with CodeScanner 2.5.2.

The significant version jump (2.0.0 -> 2.5.2) might introduce breaking changes. Please verify that the QR code scanning functionality still works as expected.

✅ Verification successful

CodeScanner update to 2.5.2 appears safe

The codebase uses only basic QR scanning functionality that remains unchanged in version 2.x. All usage patterns are compatible with the updated version.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CodeScanner usage to identify potential compatibility issues
rg -l "CodeScanner" | while read -r file; do
  if [[ "$file" =~ \.swift$ ]]; then
    echo "=== $file ==="
    rg "import.*CodeScanner|CodeScanner" "$file" -A 5
  fi
done

Length of output: 3361


45-46: Verify SimpleToast integration after version bump.

The update from 0.8.1 to 0.10.1 might introduce breaking changes in the toast notification system. Please verify that all toast notifications still work as expected.

✅ Verification successful

SimpleToast integration verified successfully after version bump

The current implementation uses stable SimpleToast APIs (basic presentation binding and standard configuration options) that are compatible across versions 0.8.1 and 0.10.1. No breaking changes impact detected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for SimpleToast usage
echo "=== Checking Toast Usage ==="
rg "import.*SimpleToast|\.toast" -A 3

Length of output: 336


Script:

#!/bin/bash
# Search for toast configurations and usage in BitcoinView
echo "=== Checking Toast Configuration and Usage ==="
rg "\.toast|ToastStyle|showToast" BitcoinView.swift -A 5

echo -e "\n=== Checking View Implementation ==="
ast-grep --pattern 'struct BitcoinView: View {
  $$$
  var body: some View {
    $$$
  }
  $$$
}'

Length of output: 408


Script:

#!/bin/bash
# Find the correct path to BitcoinView.swift
echo "=== Finding BitcoinView.swift ==="
fd BitcoinView.swift

echo -e "\n=== Checking Toast Configuration and Usage ==="
fd BitcoinView.swift --exec rg "\.toast|ToastStyle|showToast" {} -A 5

echo -e "\n=== Checking View Implementation ==="
fd BitcoinView.swift --exec ast-grep --pattern 'struct BitcoinView: View {
  $$$
  var body: some View {
    $$$
  }
  $$$
}' {}

Length of output: 1274


36-37: Verify LDK Node compatibility with new client implementation.

The update to ldk-node 0.4.2 aligns with the introduction of LightningNodeClient. Please ensure:

  1. All new LDK Node APIs are properly integrated into the client
  2. No deprecated APIs are being used
✅ Verification successful

LDK Node 0.4.2 integration verified successfully

The codebase correctly implements all new LDK Node APIs and shows no usage of deprecated functionality. Key verifications:

  • Proper implementation of unified QR payments and JIT channels
  • Modern event handling pattern
  • Current balance and payment APIs
  • Up-to-date channel and peer management
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for LDK Node API usage
echo "=== Checking LDK Node API Usage ==="
rg "import.*ldk_node|LDKNode" -A 5

# Search for potential deprecated API calls
echo "=== Checking Lightning Service Implementation ==="
fd -e swift | xargs rg "LightningNodeService|LightningNodeClient" -A 10

Length of output: 67323


Script:

#!/bin/bash
# Search for LightningNodeService implementation
echo "=== Checking LightningNodeService Implementation ==="
ast-grep --pattern 'class LightningNodeService {
  $$$
}'

# Search for LightningNodeClient implementation
echo "=== Checking LightningNodeClient Implementation ==="
ast-grep --pattern 'protocol LightningNodeClient {
  $$$
}'

# Search for specific API usage patterns
echo "=== Checking API Usage Patterns ==="
rg "Node\..*\(|\.connect\(|\.send_payment\(|\.receive_payment\(" -A 2

Length of output: 7897

LDKNodeMonday.xcodeproj/project.pbxproj (2)

825-825: LGTM: Development team configuration added.

The development team identifier has been properly configured for both Debug and Release configurations, which is necessary for code signing and deploying to devices.

Also applies to: 858-858


Line range hint 1012-1016: Consider updating dependency version constraints.

While using exact versions ensures reproducible builds, consider:

  1. Regularly checking for security updates
  2. Setting minimum version constraints instead of exact versions for non-critical dependencies

Run this script to check for newer versions and security advisories:

Also applies to: 1017-1021, 1022-1026, 1027-1031, 1032-1036

✅ Verification successful

Dependencies are up-to-date and well-maintained

While exact version constraints are used, all dependencies are currently at their latest versions and no security vulnerabilities were found. The consistent version management suggests active maintenance, which mitigates the primary concerns about using exact versions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for newer versions and security advisories for project dependencies

# Check latest versions on GitHub
echo "Checking latest versions..."
gh api graphql -f query='
{
  repository(owner: "lightningdevkit", name: "ldk-node") {
    releases(last: 1) { nodes { tagName } }
  }
  repository(owner: "kishikawakatsumi", name: "KeychainAccess") {
    releases(last: 1) { nodes { tagName } }
  }
  repository(owner: "sanzaru", name: "SimpleToast") {
    releases(last: 1) { nodes { tagName } }
  }
  repository(owner: "twostraws", name: "CodeScanner") {
    releases(last: 1) { nodes { tagName } }
  }
}'

# Check for security advisories
echo "Checking security advisories..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: SWIFT, package: "KeychainAccess") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
    }
  }
}'

Length of output: 1925


Script:

#!/bin/bash
# First get current versions from project file
echo "Current versions in project.pbxproj:"
rg "path = .*\.git.*tag = (.*?)," -o --replace '$1' project.pbxproj

# Check repositories individually
echo -e "\nChecking ldk-node latest release:"
gh api repos/lightningdevkit/ldk-node/releases/latest --jq .tag_name

echo -e "\nChecking KeychainAccess latest release:"
gh api repos/kishikawakatsumi/KeychainAccess/releases/latest --jq .tag_name

echo -e "\nChecking SimpleToast latest release:"
gh api repos/sanzaru/SimpleToast/releases/latest --jq .tag_name

echo -e "\nChecking CodeScanner latest release:"
gh api repos/twostraws/CodeScanner/releases/latest --jq .tag_name

# Check security advisories for all packages
for pkg in "KeychainAccess" "SimpleToast" "CodeScanner"
do
  echo -e "\nChecking security advisories for $pkg:"
  gh api graphql -f query="
  {
    securityVulnerabilities(first: 10, ecosystem: SWIFT, package: \"$pkg\") {
      nodes {
        advisory {
          summary
          severity
          publishedAt
        }
        vulnerableVersionRange
      }
    }
  }" --jq '.data.securityVulnerabilities.nodes[]'
done

Length of output: 2314


Script:

#!/bin/bash
echo "Current versions in project.pbxproj:"
rg "path = .*\.git.*tag = (.*?)," -o --replace '$1' LDKNodeMonday.xcodeproj/project.pbxproj

Length of output: 176


Script:

#!/bin/bash
echo "Searching for dependency versions in project.pbxproj:"
rg "tag|version" -A 2 -B 2 LDKNodeMonday.xcodeproj/project.pbxproj

Length of output: 578

Comment on lines +67 to +71
if lightningClient.status().isRunning {
try lightningClient.stop()
}
try LightningNodeService.shared.deleteDocuments()
try LightningNodeService.shared.deleteWallet()
try lightningClient.deleteDocuments()
try lightningClient.deleteWallet()
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address potential race condition in delete operation.

The status check and stop operation could race if the node status changes between the check and the stop call.

Consider handling the stop operation more safely:

-    if lightningClient.status().isRunning {
-        try lightningClient.stop()
-    }
+    // Attempt to stop regardless of status, handle any errors
+    try? lightningClient.stop()
     try lightningClient.deleteDocuments()
     try lightningClient.deleteWallet()
📝 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
if lightningClient.status().isRunning {
try lightningClient.stop()
}
try LightningNodeService.shared.deleteDocuments()
try LightningNodeService.shared.deleteWallet()
try lightningClient.deleteDocuments()
try lightningClient.deleteWallet()
// Attempt to stop regardless of status, handle any errors
try? lightningClient.stop()
try lightningClient.deleteDocuments()
try lightningClient.deleteWallet()

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 (1)
LDKNodeMonday/App/LDKNodeMondayApp.swift (1)

84-88: Improve error handling in applicationWillTerminate.

While using try? silently ignores errors, it might be better to log any failures during node shutdown for debugging purposes.

Consider this approach:

    func applicationWillTerminate(_ application: UIApplication) {
-        try? lightningClient?.stop()
+        do {
+            try lightningClient?.stop()
+        } catch {
+            print("Failed to stop lightning node: \(error)")
+            // Consider using a proper logging framework
+        }
    }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cc386c9 and 3fe35f1.

📒 Files selected for processing (3)
  • LDKNodeMonday/App/LDKNodeMondayApp.swift (3 hunks)
  • LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (5 hunks)
  • LDKNodeMonday/View/Home/Send/AddressView.swift (0 hunks)
💤 Files with no reviewable changes (1)
  • LDKNodeMonday/View/Home/Send/AddressView.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • LDKNodeMonday/View Model/Profile/SettingsViewModel.swift
🔇 Additional comments (3)
LDKNodeMonday/App/LDKNodeMondayApp.swift (3)

29-38: Well-structured dependency injection!

The view models are properly initialized with the lightningClient instance, following SwiftUI best practices for dependency injection. This ensures consistent state management across the view hierarchy.


64-65: Consider enhancing error handling and addressing the TODO.

While the migration to lightningClient is good, there are two areas for improvement:

  1. The TODO comment indicates that .start could accept configuration parameters from backupInfo. This would improve flexibility.
  2. The error handling could be more specific to handle different failure scenarios.

Would you like me to:

  1. Help implement the parameter passing from backupInfo to .start?
  2. Generate more specific error handling cases?

15-15: Consider thread safety implications of shared state.

While initializing a single lightningClient instance aligns with the PR objectives, accessing it through AppDelegate.shared could lead to thread safety issues if the client is accessed concurrently from multiple threads.

Consider adding synchronization mechanisms or documenting thread safety requirements. Let me verify the usage pattern:

Also applies to: 20-22

@reez reez merged commit 97bd457 into main Jan 18, 2025
1 check passed
@reez reez deleted the client branch January 18, 2025 00:02
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