Add LND test wallet

This commit is contained in:
adrianaepure
2023-06-08 09:36:06 +03:00
commit 1313d727cf
251 changed files with 57518 additions and 0 deletions

View File

@ -0,0 +1,104 @@
//
// EventBus.swift
// wallet
//
// Created by Jason van den Berg on 2020/08/18.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
public enum EventTypes: String {
case lndStateChange = "lnd-state-change"
case lndStarted = "lnd-started"
case lndStopped = "lnd-stopped"
case lndRpcReady = "lnd-rpc-ready"
case lndWalletUnlocked = "lnd-wallet-unlocked"
case lndWalletLocked = "lnd-wallet-locked"
case lndChannelUpdate = "lnd-channel-update"
}
private let identifier = "app.lndtest.wallet.eventbus"
open class EventBus {
static let shared = EventBus()
static let queue = DispatchQueue(label: identifier, attributes: [])
struct NamedObserver {
let observer: NSObjectProtocol
let eventType: EventTypes
}
var cache = [UInt: [NamedObserver]]()
// MARK: Publish
open class func postToMainThread(_ eventType: EventTypes, sender: Any? = nil) {
DispatchQueue.main.async {
NotificationCenter.default.post(name: Notification.Name(rawValue: eventType.rawValue), object: sender)
}
}
// MARK: Subscribe
@discardableResult
open class func on(_ target: AnyObject, eventType: EventTypes, sender: Any? = nil, queue: OperationQueue?, handler: @escaping ((Notification?) -> Void)) -> NSObjectProtocol {
let id = UInt(bitPattern: ObjectIdentifier(target))
let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: eventType.rawValue), object: sender, queue: queue, using: handler)
let namedObserver = NamedObserver(observer: observer, eventType: eventType)
EventBus.queue.sync {
if let namedObservers = EventBus.shared.cache[id] {
EventBus.shared.cache[id] = namedObservers + [namedObserver]
} else {
EventBus.shared.cache[id] = [namedObserver]
}
}
return observer
}
@discardableResult
open class func onMainThread(_ target: AnyObject, eventType: EventTypes, sender: Any? = nil, handler: @escaping ((Notification?) -> Void)) -> NSObjectProtocol {
return EventBus.on(target, eventType: eventType, sender: sender, queue: OperationQueue.main, handler: handler)
}
@discardableResult
open class func onBackgroundThread(_ target: AnyObject, eventType: EventTypes, sender: Any? = nil, handler: @escaping ((Notification?) -> Void)) -> NSObjectProtocol {
return EventBus.on(target, eventType: eventType, sender: sender, queue: OperationQueue(), handler: handler)
}
// MARK: Unregister
open class func unregister(_ target: AnyObject) {
let id = UInt(bitPattern: ObjectIdentifier(target))
let center = NotificationCenter.default
EventBus.queue.sync {
if let namedObservers = EventBus.shared.cache.removeValue(forKey: id) {
for namedObserver in namedObservers {
center.removeObserver(namedObserver.observer)
}
}
}
}
open class func unregister(_ target: AnyObject, eventType: EventTypes) {
let id = UInt(bitPattern: ObjectIdentifier(target))
let center = NotificationCenter.default
EventBus.queue.sync {
if let namedObservers = EventBus.shared.cache[id] {
EventBus.shared.cache[id] = namedObservers.filter({ (namedObserver: NamedObserver) -> Bool in
if namedObserver.eventType == eventType {
center.removeObserver(namedObserver.observer)
return false
} else {
return true
}
})
}
}
}
}

View File

@ -0,0 +1,32 @@
//
// LightningError.swift
// wallet
//
// Created by Jason van den Berg on 2020/09/12.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
enum LightningError: Error {
case unknown
case mapping
case invalidPassword
case paymentError(String)
}
extension LightningError: LocalizedError {
public var errorDescription: String? {
switch self {
case .unknown:
return NSLocalizedString("LND_ERROR_UNKNOWN", comment: "LND error")
case .mapping:
return NSLocalizedString("LND_ERROR_MAPPING", comment: "LND error")
case .invalidPassword:
return NSLocalizedString("LND_ERROR_INVALID_PASSWORD", comment: "LND error")
case .paymentError(let lndKey):
//TODO get all possible error keys and create custom messages for them
return String(format: NSLocalizedString("LND_ERROR_PAYMENT", comment: "LND error"), lndKey)
}
}
}

View File

@ -0,0 +1,76 @@
//
// LightningStateMonitor.swift
// wallet
//
// Created by Jason van den Berg on 2020/08/18.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class LightningMonitorState {
var lndRunning = false { didSet { onUpdate() } }
var rpcReady = false { didSet { onUpdate() } }
var walletUnlocked = false { didSet { onUpdate() } }
var walletInfo = Lnrpc_GetInfoResponse() { didSet { onUpdate() } }
var debuggingStatus: [String] {
var entries: [String] = []
entries.append("LND running: \(lndRunning ? "" : "")")
entries.append("RPC ready: \(rpcReady ? "" : "")")
entries.append("Wallet unlocked: \(walletUnlocked ? "" : "")")
if walletUnlocked {
entries.append("Synced to chain: \(walletInfo.syncedToChain ? "" : "")")
entries.append("Block height: \(walletInfo.blockHeight)")
entries.append("Peers: \(walletInfo.numPeers)")
}
return entries
}
//ALlow other components to subscribe to state changes from one place
private func onUpdate() {
EventBus.postToMainThread(.lndStateChange, sender: self)
}
}
class LightningStateMonitor {
public static let shared = LightningStateMonitor()
var state = LightningMonitorState()
private init() {
EventBus.onMainThread(self, eventType: .lndStarted) { [weak self] (_) in
self?.state.lndRunning = true
}
EventBus.onMainThread(self, eventType: .lndStopped) { [weak self] (_) in
self?.state.lndRunning = false
self?.state.walletUnlocked = false
self?.state.rpcReady = false
}
EventBus.onMainThread(self, eventType: .lndRpcReady) { [weak self] (_) in
self?.state.rpcReady = true
}
EventBus.onMainThread(self, eventType: .lndWalletUnlocked) { [weak self] (_) in
self?.state.walletUnlocked = true
}
//TODO find better way to subscribe to LND events than this
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateInfo), userInfo: nil, repeats: true)
}
@objc private func updateInfo() {
Lightning.shared.info { [weak self] (response, error) in
guard let self = self else { return }
guard error == nil else {
return self.state.walletInfo = .init()
}
self.state.walletInfo = response
}
}
}

View File

@ -0,0 +1,59 @@
//
// NodePublicKey.swift
// wallet
//
// Created by Jason van den Berg on 2020/08/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class NodePublicKey {
enum NodePublicKeyErrors: Error {
case invalidHexString
case invalidByte
case invalidByteLength
}
private let bytes: [UInt8]
let hexString: String
var data: Data {
return Data(bytes)
}
init(_ hexString: String) throws {
let length = hexString.count
// Must start with 02 or 03 as according to SECP256K1
guard hexString.hasPrefix("02") || hexString.hasPrefix("03") else {
throw NodePublicKeyErrors.invalidHexString
}
// Must be even characters
guard length & 1 == 0 else {
throw NodePublicKeyErrors.invalidHexString
}
var bytes = [UInt8]()
bytes.reserveCapacity(length / 2)
var index = hexString.startIndex
for _ in 0..<length / 2 {
let nextIndex = hexString.index(index, offsetBy: 2)
guard let byte = UInt8(hexString[index..<nextIndex], radix: 16) else {
throw NodePublicKeyErrors.invalidByte
}
bytes.append(byte)
index = nextIndex
}
// Must be 33 bytes in length for compressed bitcoin public key
guard bytes.count == 33 else {
throw NodePublicKeyErrors.invalidByteLength
}
self.bytes = bytes
self.hexString = hexString
}
}