Skip to content

Commit

Permalink
chore: lightning node client
Browse files Browse the repository at this point in the history
  • Loading branch information
reez authored Jan 18, 2025
1 parent 740f939 commit 97bd457
Show file tree
Hide file tree
Showing 34 changed files with 718 additions and 365 deletions.
4 changes: 2 additions & 2 deletions LDKNodeMonday.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"LDKNodeMonday/Preview Content\"";
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = 9G6M658RKZ;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = LDKNodeMonday/Info.plist;
Expand Down Expand Up @@ -855,7 +855,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"LDKNodeMonday/Preview Content\"";
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = 9G6M658RKZ;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = LDKNodeMonday/Info.plist;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/twostraws/CodeScanner",
"state" : {
"revision" : "d954f02dc06efe7adf24b8f62e39819235f9898c",
"version" : "2.0.0"
"revision" : "5e886430238944c7200fc9e10dbf2d9550dba865",
"version" : "2.5.2"
}
},
{
Expand All @@ -33,17 +33,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/lightningdevkit/ldk-node.git",
"state" : {
"revision" : "db66cb90e5878833f367f46c4368259efde31720",
"version" : "0.4.0"
"revision" : "21566111f1c32f6f562a15711158020fa416f1d7",
"version" : "0.4.2"
}
},
{
"identity" : "simpletoast",
"kind" : "remoteSourceControl",
"location" : "https://github.com/sanzaru/SimpleToast.git",
"state" : {
"revision" : "8dbc2e7c33cda25c0b2efafd59716cb9820c83eb",
"version" : "0.8.1"
"revision" : "99330cceeea6a9068d40ccbe27efb75d240098ef",
"version" : "0.10.1"
}
}
],
Expand Down
25 changes: 19 additions & 6 deletions LDKNodeMonday/App/LDKNodeMondayApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,30 @@ struct LDKNodeMondayApp: App {

@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

private let lightningClient: LightningNodeClient = .live
@State private var appState = AppState.loading
@State private var appError: Error?
@State private var navigationPath = NavigationPath()

init() {
AppDelegate.shared.lightningClient = lightningClient
}

var body: some Scene {
WindowGroup {
NavigationStack(path: $navigationPath) {
switch appState {
case .onboarding:
OnboardingView(viewModel: .init(appState: $appState))
OnboardingView(
viewModel: .init(appState: $appState, lightningClient: lightningClient)
)
case .wallet:
BitcoinView(
viewModel: .init(appState: $appState, priceClient: .live),
viewModel: .init(
appState: $appState,
priceClient: .live,
lightningClient: lightningClient
),
sendNavigationPath: $navigationPath
)
case .error:
Expand All @@ -50,13 +61,12 @@ struct LDKNodeMondayApp: App {
if backupInfo != nil {
do {
// TODO: .start could take parameters from backupInfo (seed, network, url, lsp)
try await LightningNodeService.shared.start()
LightningNodeService.shared.listenForEvents()
try await lightningClient.start()
lightningClient.listenForEvents()
await MainActor.run {
self.appState = .wallet
}
} catch let error {
debugPrint(error)
await MainActor.run {
self.appError = error
self.appState = .error
Expand All @@ -71,8 +81,11 @@ struct LDKNodeMondayApp: App {
}

class AppDelegate: NSObject, UIApplicationDelegate {
static let shared = AppDelegate()
var lightningClient: LightningNodeClient?

func applicationWillTerminate(_ application: UIApplication) {
try? LightningNodeService.shared.stop()
try? lightningClient?.stop()
}
}

Expand Down
150 changes: 150 additions & 0 deletions LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,153 @@ extension LightningNodeService {
try FileManager.default.deleteAllContentsInDocumentsDirectory()
}
}

struct LightningNodeClient {
let start: () async throws -> Void
let stop: () throws -> Void
let nodeId: () -> String
let newAddress: () async throws -> String
let spendableOnchainBalanceSats: () async -> UInt64
let totalOnchainBalanceSats: () async -> UInt64
let totalLightningBalanceSats: () async -> UInt64
let lightningBalances: () async -> [LightningBalance]
let pendingBalancesFromChannelClosures: () async -> [PendingSweepBalance]
let connect: (PublicKey, String, Bool) async throws -> Void
let disconnect: (PublicKey) throws -> Void
let connectOpenChannel:
(PublicKey, String, UInt64, UInt64?, ChannelConfig?, Bool) async throws -> UserChannelId
let closeChannel: (ChannelId, PublicKey) throws -> Void
let send: (String) async throws -> QrPaymentResult
let receive: (UInt64, String, UInt32) async throws -> String
let receiveViaJitChannel: (UInt64, String, UInt32, UInt64?) async throws -> Bolt11Invoice
let listPeers: () -> [PeerDetails]
let listChannels: () -> [ChannelDetails]
let listPayments: () -> [PaymentDetails]
let status: () -> NodeStatus
let deleteWallet: () throws -> Void
let getBackupInfo: () throws -> BackupInfo
let deleteDocuments: () throws -> Void
let getNetwork: () -> Network
let getNetworkColor: () -> Color
let listenForEvents: () -> Void
}

extension LightningNodeClient {
static let live = Self(
start: { try await LightningNodeService.shared.start() },
stop: { try LightningNodeService.shared.stop() },
nodeId: { LightningNodeService.shared.nodeId() },
newAddress: { try await LightningNodeService.shared.newAddress() },
spendableOnchainBalanceSats: {
await LightningNodeService.shared.spendableOnchainBalanceSats()
},
totalOnchainBalanceSats: { await LightningNodeService.shared.totalOnchainBalanceSats() },
totalLightningBalanceSats: {
await LightningNodeService.shared.totalLightningBalanceSats()
},
lightningBalances: { await LightningNodeService.shared.lightningBalances() },
pendingBalancesFromChannelClosures: {
await LightningNodeService.shared.pendingBalancesFromChannelClosures()
},
connect: { nodeId, address, persist in
try await LightningNodeService.shared.connect(
nodeId: nodeId,
address: address,
persist: persist
)
},
disconnect: { nodeId in try LightningNodeService.shared.disconnect(nodeId: nodeId) },
connectOpenChannel: { nodeId, address, amount, pushMsat, config, announce in
try await LightningNodeService.shared.connectOpenChannel(
nodeId: nodeId,
address: address,
channelAmountSats: amount,
pushToCounterpartyMsat: pushMsat,
channelConfig: config,
announceChannel: announce
)
},
closeChannel: { channelId, nodeId in
try LightningNodeService.shared.closeChannel(
userChannelId: channelId,
counterpartyNodeId: nodeId
)
},
send: { uriStr in try await LightningNodeService.shared.send(uriStr: uriStr) },
receive: { amount, message, expiry in
try await LightningNodeService.shared.receive(
amountSat: amount,
message: message,
expirySec: expiry
)
},
receiveViaJitChannel: { amount, description, expiry, maxFee in
try await LightningNodeService.shared.receiveViaJitChannel(
amountMsat: amount,
description: description,
expirySecs: expiry,
maxLspFeeLimitMsat: maxFee
)
},
listPeers: { LightningNodeService.shared.listPeers() },
listChannels: { LightningNodeService.shared.listChannels() },
listPayments: { LightningNodeService.shared.listPayments() },
status: { LightningNodeService.shared.status() },
deleteWallet: { try LightningNodeService.shared.deleteWallet() },
getBackupInfo: { try LightningNodeService.shared.getBackupInfo() },
deleteDocuments: { try LightningNodeService.shared.deleteDocuments() },
getNetwork: { LightningNodeService.shared.network },
getNetworkColor: { LightningNodeService.shared.networkColor },
listenForEvents: {}
)
}

#if DEBUG
extension LightningNodeClient {
static let mock = Self(
start: {},
stop: {},
nodeId: { "038474837483784378437843784378437843784378" },
newAddress: { "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" },
spendableOnchainBalanceSats: { 100_000 },
totalOnchainBalanceSats: { 150_000 },
totalLightningBalanceSats: { 50_000 },
lightningBalances: { [] },
pendingBalancesFromChannelClosures: { [] },
connect: { _, _, _ in },
disconnect: { _ in },
connectOpenChannel: { _, _, _, _, _, _ in UserChannelId("abcdef") },
closeChannel: { _, _ in },
send: { _ in QrPaymentResult.onchain(txid: "txid") },
receive: { _, _, _ in "lightning:lnbc1..." },
receiveViaJitChannel: { _, _, _, _ in Bolt11Invoice("lnbc1...") },
listPeers: { [] },
listChannels: { [] },
listPayments: { [] },
status: {
NodeStatus(
isRunning: true,
isListening: true,
currentBestBlock: BestBlock(
blockHash: BlockHash(
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
),
height: 123456
),
latestLightningWalletSyncTimestamp: UInt64(Date().timeIntervalSince1970),
latestOnchainWalletSyncTimestamp: UInt64(Date().timeIntervalSince1970),
latestFeeRateCacheUpdateTimestamp: UInt64(Date().timeIntervalSince1970),
latestRgsSnapshotTimestamp: UInt64(Date().timeIntervalSince1970),
latestNodeAnnouncementBroadcastTimestamp: UInt64(Date().timeIntervalSince1970),
latestChannelMonitorArchivalHeight: 123456
)
},
deleteWallet: {},
getBackupInfo: { BackupInfo(mnemonic: "test test test") },
deleteDocuments: {},
getNetwork: { .signet },
getNetworkColor: { .orange },
listenForEvents: {}
)
}
#endif
22 changes: 15 additions & 7 deletions LDKNodeMonday/View Model/Home/BitcoinViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,58 @@ class BitcoinViewModel: ObservableObject {
@Published var isTotalBalanceFinished: Bool = false
@Published var isTotalLightningBalanceFinished: Bool = false
@Published var isPriceFinished: Bool = false

let lightningClient: LightningNodeClient
let priceClient: PriceClient
var price: Double = 0.00
var time: Int?

var satsPrice: String {
let usdValue = Double(totalBalance).valueInUSD(price: price)
return usdValue
}

var totalUSDValue: String {
let totalUSD = Double(totalBalance + totalLightningBalance).valueInUSD(price: price)
return totalUSD
}

init(appState: Binding<AppState>, priceClient: PriceClient) {
init(
appState: Binding<AppState>,
priceClient: PriceClient,
lightningClient: LightningNodeClient
) {
_appState = appState
self.priceClient = priceClient
self.lightningClient = lightningClient
}

func getStatus() async {
let status = LightningNodeService.shared.status()
let status = lightningClient.status()
DispatchQueue.main.async {
self.status = status
self.isStatusFinished = true
}
}

func getTotalOnchainBalanceSats() async {
let balance = await LightningNodeService.shared.totalOnchainBalanceSats()
let balance = await lightningClient.totalOnchainBalanceSats()
DispatchQueue.main.async {
self.totalBalance = balance
self.isTotalBalanceFinished = true
}
}

func getSpendableOnchainBalanceSats() async {
let balance = await LightningNodeService.shared.spendableOnchainBalanceSats()
let balance = await lightningClient.spendableOnchainBalanceSats()
DispatchQueue.main.async {
self.spendableBalance = balance
self.isSpendableBalanceFinished = true
}
}

func getTotalLightningBalanceSats() async {
let balance = await LightningNodeService.shared.totalLightningBalanceSats()
let balance = await lightningClient.totalLightningBalanceSats()
DispatchQueue.main.async {
self.totalLightningBalance = balance
self.isTotalLightningBalanceFinished = true
Expand Down Expand Up @@ -95,10 +104,9 @@ class BitcoinViewModel: ObservableObject {
}

func getColor() {
let color = LightningNodeService.shared.networkColor
let color = lightningClient.getNetworkColor()
DispatchQueue.main.async {
self.networkColor = color
}
}

}
Loading

0 comments on commit 97bd457

Please sign in to comment.