// // ViewModel.swift // wallet // // Created by Jason on 8/23/20. // Copyright © 2020 Jason. All rights reserved. // import Foundation struct WalletBalance{ let total: Int let confirmed: Int let unconfirmed: Int } class ViewModel { //TODO: Hardcoded values. Change these later.mailto:0245fc5e867abb5b83ead35b50dc5013dd358b9f3eb48c02f5e1cc9fc675039359@uld2jqbrrwsowhxobvxlrl6j7qc2rmccsmnnf6ba4jepkugxqkyohvad.onion:9735 private var nodePubKey = try! NodePublicKey("0245fc5e867abb5b83ead35b50dc5013dd358b9f3eb48c02f5e1cc9fc675039359") private var hostAddress = "bmadesign.go.ro" private var hostPort: UInt = 9735 private let closeAddress = "tb1qylxttvn7wm7vsc2j36cjvmpl7nykcrzqkz6avl" let newAddress = Observable() private let exampleRepo = ExampleRepository() let isLoading = Observable() let lightningRepo = LightningRepository() let walletWipe = Observable() let walletBalance = Observable() let channelBalance = Observable() let lndInfo = Observable() let channels = Observable<[Lnrpc_Channel]>() let closedChannels = Observable<[Lnrpc_ChannelCloseSummary]>() let pendingChannels = Observable() let peers = Observable<[Lnrpc_Peer]>() let invoices = Observable<[Lnrpc_Invoice]>() let payments = Observable<[Lnrpc_Payment]>() required init() { // Empty } //MARK: - LND func load() { isLoading.value = true // This is an example of a fetch to some data provider (i.e. an http api or something else) // and where you can place the observed response exampleRepo.getRandomInt( onSuccess: { [weak self] someInt in self?.isLoading.value = false }, onFailure: { [weak self] error in self?.isLoading.value = false }) } func getInfo() { self.isLoading.value = true lightningRepo.getInfo { [weak self] (res) in self?.isLoading.value = false self?.lndInfo.value = res debugPrint("Response get Info", res) } onFailure: { [weak self] (error) in self?.isLoading.value = false } } func getNewAddress() { self.isLoading.value = true lightningRepo.getNewAddress( onSuccess: { [weak self] address in self?.isLoading.value = false self?.newAddress.value = address debugPrint("Address :", address) }, onFailure: { [weak self] error in self?.isLoading.value = false debugPrint(error?.localizedDescription as Any) }) } //MARK: - Wallet func createWallet(password: String) { self.isLoading.value = true lightningRepo.createWallet( password: password, onSuccess: { [weak self] seed in self?.isLoading.value = false }, onFailure: { [weak self] error in self?.isLoading.value = false }) } func unlockWallet(password: String) { self.isLoading.value = true lightningRepo.unlockWallet( password: password, onSuccess: { [weak self] in self?.isLoading.value = false self?.getInfo() self?.getWalletBalance() }, onFailure: { [weak self] error in self?.isLoading.value = false debugPrint(error?.localizedDescription as Any) }) } func getWalletBalance() { lightningRepo.getWalletBalance( onSuccess: { [weak self] (total, confirmed, unconfirmed) in self?.walletBalance.value = WalletBalance(total: Int(total), confirmed: Int(confirmed), unconfirmed: Int(unconfirmed)) }, onFailure: { error in debugPrint("Wallet balance error", error?.localizedDescription as Any) // TODO: Change to error }) } func wipeWallet() { self.isLoading.value = true lightningRepo.wipeWallet( onSuccess: { [weak self] in self?.isLoading.value = false self?.walletWipe.value = () }, onFailure: { [weak self] error in self?.isLoading.value = false debugPrint(error?.localizedDescription as Any) }) } //MARK: - Channels func openChannel(nodePubKey: String, hostAddress: String, port: UInt, pushSat: Int, localFunding: Int, onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) { debugPrint("Node pub key", nodePubKey, hostAddress, port, pushSat, localFunding) lightningRepo.openChannel( localFunding: Int64(localFunding), pushSat: Int64(pushSat), host: hostAddress, port: port, nodePubKey: try! NodePublicKey(nodePubKey), closeAddress: nil, onSuccess: { message in onSuccess(message) }, onFailure: { error in onFailure(error) }) } func closeChannel(channel:Lnrpc_Channel, onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) { lightningRepo.closeChannel(channel: channel) { response in self.listChannels() debugPrint("Response", response) } onFailure: { error in debugPrint("Error", error) } } func listChannels() { self.isLoading.value = true lightningRepo.listChannels(onSuccess: { [weak self] (response) in self?.isLoading.value = false self?.channels.value = response.channels.sorted{$0.uptime > $1.uptime} debugPrint("Channels response ", response) }) { [weak self] (error) in self?.isLoading.value = false } } func listClosedChannels() { self.isLoading.value = true lightningRepo.listClosedChannels(onSuccess: { [weak self] (response) in self?.isLoading.value = false self?.closedChannels.value = response.channels debugPrint("Channels response ", response) }) { [weak self] (error) in self?.isLoading.value = false } } func listPendingChannels() { self.isLoading.value = true lightningRepo.listPendingChannels(onSuccess: { [weak self] (response) in self?.isLoading.value = false self?.pendingChannels.value = response debugPrint("Channels response ", response) }) { [weak self] (error) in self?.isLoading.value = false } } func getChannelBalance(){ lightningRepo.getLightningChannelBalance { balance in self.channelBalance.value = Int(balance.balance) debugPrint("Channel balance", balance) } onFailure: { error in debugPrint("Channel balance error", error.debugDescription) } } func getChannelInfo(id: UInt64, onSuccess: @escaping (Lnrpc_ChannelEdge) -> Void, onFailure: @escaping (Error?) -> Void) { lightningRepo.getChannelInfo(id: id) { (channel) in onSuccess(channel) } onFailure: { (error) in onFailure(error) } } //MARK: - Peers func listPeers(){ lightningRepo.listPeers { res in debugPrint("Listing peers response", res.peers) self.peers.value = res.peers if res.peers.count > 0 { if let pubKey = res.peers.first?.pubKey { self.nodePubKey = try! NodePublicKey(pubKey) if let address = res.peers.first?.address{ let addressArray = address.split(separator: ":") self.hostAddress = addressArray[0].description self.hostPort = UInt(addressArray[1].description) ?? 9735 } } } } onFailure: { error in debugPrint("Listing peers error", error ?? "") } } //MARK: - Payments func listPayments(){ self.isLoading.value = true lightningRepo.listPayments { [weak self] (response) in self?.isLoading.value = false debugPrint("Response", response.payments) self?.payments.value = response.payments.sorted{$0.creationDate > $1.creationDate} } onFailure: { error in debugPrint("Listing payments error", error ?? "") self.isLoading.value = false debugPrint(error?.localizedDescription as Any) } } func getPaymentInfo(invoice: String, onSuccess: @escaping (Lnrpc_PayReq) -> Void, onFailure: @escaping (Error?) -> Void) { lightningRepo.getPaymentInfo(paymentRequest: invoice, onSuccess: {onSuccess($0)}, onFailure: {onFailure($0)}) } //MARK: - Invoices func estimateFee(address: String, amount: Int, onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) { lightningRepo.estimateFee(address: address, amount: Int64(amount)) { response in debugPrint("Fee estimator response", response) } onFailure: { error in debugPrint("Fee estimator error", error.debugDescription) } } func feeReport(onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) { lightningRepo.feeReport() { response in debugPrint("Fee report response", response) } onFailure: { error in debugPrint("Fee report error", error.debugDescription) } } func createInvoice(amount: Int, comment: String, onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) { self.isLoading.value = true lightningRepo.createInvoice(amount: amount, memo: comment, onSuccess: { (response) in self.isLoading.value = false onSuccess(response.paymentRequest) },onFailure: { error in self.isLoading.value = false onFailure(error) }) } func payInvoice(invoice: String, onSuccess: @escaping (Lnrpc_SendResponse) -> Void, onFailure: @escaping (Error?) -> Void) { self.isLoading.value = true lightningRepo.pay(paymentRequest: invoice, onSuccess: { [weak self] (response) in self?.isLoading.value = false onSuccess(response) },onFailure: { [weak self] error in self?.isLoading.value = false debugPrint(error?.localizedDescription as Any) onFailure(error) }) } func listInvoices(){ self.isLoading.value = true lightningRepo.listInvoices(onSuccess: { [weak self] (response) in self?.isLoading.value = false debugPrint("Response", response.invoices) self?.invoices.value = response.invoices.sorted{$0.creationDate > $1.creationDate} }) { [weak self] (error) in self?.isLoading.value = false debugPrint(error?.localizedDescription as Any) } } }