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

37
wallet/AppDelegate.swift Normal file
View File

@ -0,0 +1,37 @@
//
// AppDelegate.swift
// wallet
//
// Created by Jason on 8/12/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}

View File

@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_back.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,107 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
0.000000 1.000000 -1.000000 0.000000 4.000000 11.166626 cm
0.000000 0.000000 0.000000 scn
1.833333 -18.000000 m
1.833333 2.000000 l
-0.166667 2.000000 l
-0.166667 -18.000000 l
1.833333 -18.000000 l
h
f
n
Q
q
0.000000 1.000000 -1.000000 0.000000 14.828369 7.000000 cm
0.000000 0.000000 0.000000 scn
-0.707107 8.535476 m
-1.414214 7.828369 l
0.000000 6.414155 l
0.707107 7.121263 l
-0.707107 8.535476 l
h
5.000000 12.828369 m
5.707107 13.535476 l
5.000000 14.242582 l
4.292893 13.535476 l
5.000000 12.828369 l
h
9.292893 7.121263 m
10.000000 6.414155 l
11.414213 7.828369 l
10.707107 8.535476 l
9.292893 7.121263 l
h
0.707107 7.121263 m
5.707107 12.121263 l
4.292893 13.535476 l
-0.707107 8.535476 l
0.707107 7.121263 l
h
4.292893 12.121263 m
9.292893 7.121263 l
10.707107 8.535476 l
5.707107 13.535476 l
4.292893 12.121263 l
h
f
n
Q
endstream
endobj
3 0 obj
862
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Type /Catalog
/Pages 5 0 R
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000000952 00000 n
0000000974 00000 n
0000001147 00000 n
0000001221 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1280
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_backspace.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,91 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.974976 4.000000 cm
0.000000 0.000000 0.000000 scn
22.025000 16.000000 m
7.025000 16.000000 l
6.725000 16.000000 6.425000 15.900000 6.225000 15.700000 c
0.225000 8.700000 l
-0.075000 8.299999 -0.075000 7.799999 0.225000 7.400000 c
6.225000 0.400000 l
6.425000 0.099999 6.725000 0.000000 7.025000 0.000000 c
22.025000 0.000000 l
22.625000 0.000000 23.025000 0.400000 23.025000 1.000000 c
23.025000 15.000000 l
23.025000 15.600000 22.625000 16.000000 22.025000 16.000000 c
h
16.424999 6.000000 m
15.025000 4.600000 l
13.025000 6.600000 l
11.025000 4.600000 l
9.625000 6.000000 l
11.625000 8.000000 l
9.625000 10.000000 l
11.025000 11.400000 l
13.025000 9.400000 l
15.025000 11.400000 l
16.424999 10.000000 l
14.424999 8.000000 l
16.424999 6.000000 l
h
f
n
Q
endstream
endobj
3 0 obj
824
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Type /Catalog
/Pages 5 0 R
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000000914 00000 n
0000000936 00000 n
0000001109 00000 n
0000001183 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1242
%%EOF

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_5" orientation="portrait" appearance="dark"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" systemColor="systemMintColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<systemColor name="systemMintColor">
<color red="0.0" green="0.7803921568627451" blue="0.74509803921568629" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

Binary file not shown.

Binary file not shown.

Binary file not shown.

67
wallet/Info.plist Normal file
View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIAppFonts</key>
<array>
<string></string>
<string>sofia_pro_bold.ttf</string>
<string>sofia_pro_medium.ttf</string>
<string>sofia_pro_regular.ttf</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSCameraUsageDescription</key>
<string>Scan QR</string>
</dict>
</plist>

View File

@ -0,0 +1,451 @@
//
// Lightning.swift
//
//
// Created by Jason van den Berg on 2020/08/02.
//
import Foundation
class Lightning {
static let shared = Lightning()
private var storage: URL {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let directory = documentsDirectory.appendingPathComponent("lnd")
if !FileManager.default.fileExists(atPath: directory.path) {
try! FileManager.default.createDirectory(atPath: directory.path, withIntermediateDirectories: true)
}
return directory
}
private let confName = "lnd.conf"
private var confFile: URL {
return storage.appendingPathComponent(confName)
}
//Ensure it stays a singleton
private init() {}
func start(_ completion: @escaping (Error?) -> Void, onRpcReady: @escaping (Error?) -> Void) {
print("LND Start Request")
//Delete previous config if it exists
try? FileManager.default.removeItem(at: confFile)
//Copy new config into LND directory
do {
//TODO build this config file in code
let originalConf = "lnd.conf"
try FileManager.default.copyItem(at: Bundle.main.bundleURL.appendingPathComponent(originalConf), to: confFile)
} catch {
return completion(error)
}
let args = "--lnddir=\(storage.path)"
print(args)
LndmobileStart(
args,
LndEmptyResponseCallback { (error) in
completion(error)
if error == nil {
EventBus.postToMainThread(.lndStarted)
}
},
LndEmptyResponseCallback { (error) in
onRpcReady(error)
if error == nil {
EventBus.postToMainThread(.lndRpcReady)
}
}
)
}
func stop(_ completion: @escaping (Error?) -> Void) {
print("LND Stop Request")
do {
LndmobileStopDaemon(
try Lnrpc_StopRequest().serializedData(),
LndCallback<Lnrpc_StopResponse>({ (response, error) in
completion(error)
if error == nil {
EventBus.postToMainThread(.lndStopped)
}
})
)
completion(nil) //TODO figure out why callback is never hit by LndGenericCallback
} catch {
completion(error)
}
}
func generateSeed(_ completion: @escaping ([String], Error?) -> Void) {
do {
LndmobileGenSeed(
try Lnrpc_GenSeedRequest().serializedData(),
LndCallback<Lnrpc_GenSeedResponse> { (response, error) in
completion(response.cipherSeedMnemonic, error)
}
)
} catch {
completion([], error)
}
}
func createWallet(password: String, cipherSeedMnemonic: [String], completion: @escaping (Error?) -> Void) {
guard let passwordData = password.data(using: .utf8) else {
return completion(LightningError.invalidPassword)
}
var request = Lnrpc_InitWalletRequest()
request.cipherSeedMnemonic = cipherSeedMnemonic
request.walletPassword = passwordData
do {
LndmobileInitWallet(
try request.serializedData(),
LndEmptyResponseCallback { (error) in
completion(error)
if error == nil {
EventBus.postToMainThread(.lndWalletUnlocked)
}
}
)
} catch {
return completion(error)
}
}
func unlockWalet(password: String, completion: @escaping (Error?) -> Void) {
guard let passwordData = password.data(using: .utf8) else {
return completion(LightningError.invalidPassword)
}
var request = Lnrpc_UnlockWalletRequest()
request.walletPassword = passwordData
do {
LndmobileUnlockWallet(
try request.serializedData(),
LndEmptyResponseCallback { (error) in
completion(error)
if error == nil {
EventBus.postToMainThread(.lndWalletUnlocked)
}
}
)
} catch {
return completion(error)
}
}
func walletBalance(_ completion: @escaping (Lnrpc_WalletBalanceResponse, Error?) -> Void) {
do {
LndmobileWalletBalance(try Lnrpc_WalletBalanceRequest().serializedData(), LndCallback<Lnrpc_WalletBalanceResponse>(completion))
} catch {
completion(Lnrpc_WalletBalanceResponse(), error)
}
}
func lightningChannelBalance(_ completion: @escaping (Lnrpc_ChannelBalanceResponse, Error?) -> Void) {
do {
LndmobileChannelBalance(try Lnrpc_ChannelBalanceRequest().serializedData(),
LndCallback<Lnrpc_ChannelBalanceResponse>(completion))
} catch {
completion(Lnrpc_ChannelBalanceResponse(), error)
}
}
func info(_ completion: @escaping (Lnrpc_GetInfoResponse, Error?) -> Void) {
do {
LndmobileGetInfo(try Lnrpc_GetInfoRequest().serializedData(), LndCallback<Lnrpc_GetInfoResponse>(completion))
} catch {
completion(Lnrpc_GetInfoResponse(), error)
}
}
func newAddress(_ completion: @escaping (String, Error?) -> Void) {
do {
LndmobileNewAddress(
try Lnrpc_NewAddressRequest().serializedData(),
LndCallback<Lnrpc_NewAddressResponse> { (response, error) in
completion(response.address, error)
}
)
} catch {
completion("", error)
}
}
func listPeers(completion: @escaping (Lnrpc_ListPeersResponse, Error?) -> Void) {
LndmobileListPeers(try Data(), LndCallback<Lnrpc_ListPeersResponse>(completion))
}
func connectToNode(nodePubkey: NodePublicKey, hostAddress: String, hostPort: UInt, _ completion: @escaping (Lnrpc_ConnectPeerResponse, Error?) -> Void) {
var request = Lnrpc_ConnectPeerRequest()
var addr = Lnrpc_LightningAddress()
addr.pubkey = nodePubkey.hexString
addr.host = "\(hostAddress):\(hostPort)"
request.addr = addr
request.perm = true
do {
LndmobileConnectPeer(try request.serializedData(), LndCallback<Lnrpc_ConnectPeerResponse>(completion))
} catch {
completion(Lnrpc_ConnectPeerResponse(), error)
}
}
func openChannel(localFundingAmount: Int64, pushSat: Int64, closeAddress: String?, nodePubkey: NodePublicKey, _ completion: @escaping (Lnrpc_OpenStatusUpdate, Error?) -> Void) {
var request = Lnrpc_OpenChannelRequest()
request.localFundingAmount = localFundingAmount
if let closeAddress = closeAddress{
request.closeAddress = closeAddress
}
request.nodePubkey = nodePubkey.data
request.pushSat = pushSat
//TODO have the below config driven
request.minConfs = 2
request.targetConf = 2
request.spendUnconfirmed = false
do {
LndmobileOpenChannel(try request.serializedData(), LndCallback<Lnrpc_OpenStatusUpdate>(completion))
} catch {
completion(Lnrpc_OpenStatusUpdate(), nil)
}
}
func closeChannel(channel: Lnrpc_Channel, _ completion: @escaping (Lnrpc_ClosedChannelsResponse, Error?) -> Void) {
var request = Lnrpc_CloseChannelRequest()
request.channelPoint = Lnrpc_ChannelPoint()
let ch = channel.channelPoint.split(separator: ":")
if ch.count == 2{
request.channelPoint.fundingTxidStr = String(ch[0])
request.channelPoint.outputIndex = UInt32(ch[1]) ?? 1
}
debugPrint("channel \(channel), point \(channel.channelPoint), property list \(channel.channelPoint.propertyList())")
do {
LndmobileCloseChannel(try request.serializedData(), LndCallback<Lnrpc_ClosedChannelsResponse>(completion))
} catch {
completion(Lnrpc_ClosedChannelsResponse(), nil)
}
}
func listChannels(_ completion: @escaping (Lnrpc_ListChannelsResponse, Error?) -> Void) {
do {
LndmobileListChannels(
try Lnrpc_ListChannelsRequest().serializedData(),
LndCallback<Lnrpc_ListChannelsResponse> { (response, error) in
completion(response, error)
}
)
} catch {
completion(Lnrpc_ListChannelsResponse(), error)
}
}
func listClosedChannels(_ completion: @escaping (Lnrpc_ClosedChannelsResponse, Error?) -> Void) {
do {
LndmobileClosedChannels(
try Lnrpc_ClosedChannelsRequest().serializedData(),
LndCallback<Lnrpc_ClosedChannelsResponse> { (response, error) in
completion(response, error)
}
)
} catch {
completion(Lnrpc_ClosedChannelsResponse(), error)
}
}
func abandonChannel(pendingOpenChannel:Lnrpc_PendingChannelsResponse.PendingOpenChannel, _ completion: @escaping (Lnrpc_AbandonChannelResponse, Error?) -> Void) {
var request = Lnrpc_AbandonChannelRequest()
do {
request.channelPoint = try Lnrpc_ChannelPoint(jsonString: pendingOpenChannel.channel.channelPoint)
LndmobileListChannels(
try request.serializedData(),
LndCallback<Lnrpc_AbandonChannelResponse> { (response, error) in
debugPrint("Response Abandon channel", response, error)
completion(response, error)
}
)
} catch {
completion(Lnrpc_AbandonChannelResponse(), error)
}
}
func listPendingChannels(_ completion: @escaping (Lnrpc_PendingChannelsResponse, Error?) -> Void) {
do {
LndmobilePendingChannels(
try Lnrpc_PendingChannelsRequest().serializedData(),
LndCallback<Lnrpc_PendingChannelsResponse> { (response, error) in
completion(response, error)
}
)
} catch {
completion(Lnrpc_PendingChannelsResponse(), error)
}
}
func getChanInfo(id: UInt64, _ completion: @escaping (Lnrpc_ChannelEdge, Error?) -> Void) {
var request = Lnrpc_ChanInfoRequest()
request.chanID = id
do {
LndmobileGetChanInfo(try request.serializedData(), LndCallback<Lnrpc_ChannelEdge>(completion))
} catch {
completion(Lnrpc_ChannelEdge(), nil)
}
}
func decodePaymentRequest(_ paymentRequest: String, _ completion: @escaping (Lnrpc_PayReq, Error?) -> Void) {
var request = Lnrpc_PayReqString()
request.payReq = paymentRequest
do {
LndmobileDecodePayReq(try request.serializedData(), LndCallback<Lnrpc_PayReq>(completion))
} catch {
completion(Lnrpc_PayReq(), nil)
}
}
func listInvoices(completion: @escaping(Lnrpc_ListInvoiceResponse, Error?) -> Void){
do {
LndmobileListInvoices(
try Lnrpc_ListInvoiceRequest().serializedData(),
LndCallback<Lnrpc_ListInvoiceResponse>{ (response, error) in
completion(response, error)
}
)
} catch {
completion(Lnrpc_ListInvoiceResponse(), error)
}
}
func listPayments(completion: @escaping(Lnrpc_ListPaymentsResponse, Error?) -> Void){
do {
LndmobileListPayments(
try Lnrpc_ListPaymentsRequest().serializedData(),
LndCallback<Lnrpc_ListPaymentsResponse>{ (response, error) in
completion(response, error)
}
)
} catch {
completion(Lnrpc_ListPaymentsResponse(), error)
}
}
func payRequest(_ paymentRequest: String, _ completion: @escaping (Lnrpc_SendResponse, Error?) -> Void) {
var request = Lnrpc_SendRequest()
request.paymentRequest = paymentRequest
do {
//LND returns payment errors in the response and not with a real error. This just intercepts the callback and will return the custom error if applicable.
LndmobileSendPaymentSync(
try request.serializedData(),
LndCallback<Lnrpc_SendResponse> { (response, error) in
completion(response, error)
})
} catch {
completion(Lnrpc_SendResponse(), nil)
}
}
func createPayRequest(amount: Int, memo: String, _ completion: @escaping (Lnrpc_AddInvoiceResponse, Error?) -> Void) {
let request = Lnrpc_Invoice(amount: amount, memo: memo, expiry: .oneDay)
do {
LndmobileAddInvoice(
try request.serializedData(),
LndCallback<Lnrpc_AddInvoiceResponse>{ (response, error) in
guard response.paymentRequest.isEmpty else {
completion(response, error)
return
}
completion(response, error)
})
} catch {
completion(Lnrpc_AddInvoiceResponse(), nil)
}
}
func queryRequestFee(key: String, _ completion: @escaping (Lnrpc_QueryRoutesResponse, Error?) -> Void) {
var request = Lnrpc_QueryRoutesRequest()
request.pubKey = key
do {
LndmobileQueryRoutes(
try request.serializedData(),
LndCallback<Lnrpc_QueryRoutesResponse>{ (response, error) in
completion(response, error)
})
} catch {
completion(Lnrpc_QueryRoutesResponse(), nil)
}
}
func estimateFee(_ paymentRequest: String, amount:Int64, _ completion: @escaping (Lnrpc_EstimateFeeResponse, Error?) -> Void) {
var request = Lnrpc_EstimateFeeRequest()
request.addrToAmount = [paymentRequest:amount]
do {
LndmobileEstimateFee(
try request.serializedData(),
LndCallback<Lnrpc_EstimateFeeResponse>{ (response, error) in
completion(response, error)
})
} catch {
completion(Lnrpc_EstimateFeeResponse(), nil)
}
}
func feeReport(_ completion: @escaping (Lnrpc_FeeReportResponse, Error?) -> Void) {
let request = Lnrpc_FeeReportRequest()
do {
LndmobileFeeReport(
try request.serializedData(),
LndCallback<Lnrpc_FeeReportResponse>{ (response, error) in
completion(response, error)
})
} catch {
completion(Lnrpc_FeeReportResponse(), nil)
}
}
}
//Utils
extension Lightning {
func purge() {
//TODO ensure testnet only
print("WARNING: removing existing LND directory")
try! FileManager.default.removeItem(at: storage)
}
}
extension Lnrpc_Invoice {
init(amount: Int?, memo: String?, expiry: ExpiryTime?) {
self.init()
if let amount = amount {
value = Int64(amount)
}
if let memo = memo {
self.memo = memo
}
if let expiry = expiry {
self.expiry = Int64(expiry.rawValue)
}
`private` = true
}
}
public enum ExpiryTime: Int, Codable, CaseIterable {
case oneMinute = 60
case tenMinutes = 600 // 60 * 10
case thirtyMinutes = 1800 // 60 * 30
case oneHour = 3600 // 60 * 60
case sixHours = 21600 // 60 * 60 * 6
case oneDay = 86400 // 60 * 60 * 24
case oneWeek = 604800 // 60 * 60 * 24 * 7
case thirtyDays = 2592000 // 60 * 60 * 24 * 30
case oneYear = 31536000 // 60 * 60 * 24 * 365
}

View File

@ -0,0 +1,71 @@
//
// LndCallbacks.swift
// PayUp
//
// Created by Jason van den Berg on 2020/08/03.
// Copyright © 2020 Jason van den Berg. All rights reserved.
//
import Foundation
import SwiftProtobuf
extension Lightning {
/// Generic callback for LND function which will map responses back into the protobuf message type.
class LndCallback<T: SwiftProtobuf.Message>: NSObject, LndmobileCallbackProtocol, LndmobileRecvStreamProtocol {
let completion: (T, Error?) -> Void
init(_ completion: @escaping (T, Error?) -> Void) {
let startedOnMainThread = Thread.current.isMainThread
self.completion = { (response, error) in
if startedOnMainThread {
DispatchQueue.main.async { completion(response, error) }
} else {
completion(response, error)
}
}
}
func onResponse(_ p0: Data?) {
guard let data = p0 else {
completion(T(), nil) //For calls like balance checks, an empty response should just be `T` defaults
return
}
do {
completion(try T(serializedData: data), nil)
} catch {
completion(T(), LightningError.mapping)
}
}
func onError(_ p0: Error?) {
completion(T(), p0 ?? LightningError.unknown)
}
}
/// For LND callbacks that don't pass back any messages but can return errors
class LndEmptyResponseCallback: NSObject, LndmobileCallbackProtocol {
let completion: (Error?) -> Void
init(_ completion: @escaping (Error?) -> Void) {
let startedOnMainThread = Thread.current.isMainThread
self.completion = { error in
if startedOnMainThread {
DispatchQueue.main.async { completion(error) }
} else {
completion(error)
}
}
}
func onResponse(_ p0: Data?) {
completion(nil)
}
func onError(_ p0: Error?) {
completion(p0 ?? LightningError.unknown)
}
}
}

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
}
}

View File

@ -0,0 +1,25 @@
[Application Options]
debuglevel=trace
no-macaroons=true
nolisten=true
[Routing]
routing.assumechanvalid=true
[Bitcoin]
bitcoin.active=true
bitcoin.testnet=true
bitcoin.node=neutrino
[Neutrino]
neutrino.connect=btcd-testnet.lightning.computer
neutrino.feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json
[autopilot]
autopilot.active=false
[watchtower]
watchtower.active=false

27
wallet/Lightning/lnd.conf Normal file
View File

@ -0,0 +1,27 @@
[Application Options]
debuglevel=info
no-macaroons=true
nolisten=true
norest=true
alias=LndTest
color=#FFEA00
[Routing]
routing.assumechanvalid=true
[Bitcoin]
bitcoin.active=true
bitcoin.testnet=true
bitcoin.node=neutrino
[Neutrino]
neutrino.connect=faucet.lightning.community
neutrino.addpeer=faucet.lightning.community
neutrino.feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json
[autopilot]
autopilot.active=false
[watchtower]
watchtower.active=false

View File

@ -0,0 +1,389 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: autopilotrpc/autopilot.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Autopilotrpc_StatusRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Autopilotrpc_StatusResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Indicates whether the autopilot is active or not.
var active: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Autopilotrpc_ModifyStatusRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Whether the autopilot agent should be enabled or not.
var enable: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Autopilotrpc_ModifyStatusResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Autopilotrpc_QueryScoresRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var pubkeys: [String] = []
/// If set, we will ignore the local channel state when calculating scores.
var ignoreLocalState: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Autopilotrpc_QueryScoresResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var results: [Autopilotrpc_QueryScoresResponse.HeuristicResult] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
struct HeuristicResult {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var heuristic: String = String()
var scores: Dictionary<String,Double> = [:]
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
init() {}
}
struct Autopilotrpc_SetScoresRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The name of the heuristic to provide scores to.
var heuristic: String = String()
///
///A map from hex-encoded public keys to scores. Scores must be in the range
///[0.0, 1.0].
var scores: Dictionary<String,Double> = [:]
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Autopilotrpc_SetScoresResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "autopilotrpc"
extension Autopilotrpc_StatusRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".StatusRequest"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_StatusRequest, rhs: Autopilotrpc_StatusRequest) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_StatusResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".StatusResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "active"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBoolField(value: &self.active)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.active != false {
try visitor.visitSingularBoolField(value: self.active, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_StatusResponse, rhs: Autopilotrpc_StatusResponse) -> Bool {
if lhs.active != rhs.active {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_ModifyStatusRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ModifyStatusRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "enable"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBoolField(value: &self.enable)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.enable != false {
try visitor.visitSingularBoolField(value: self.enable, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_ModifyStatusRequest, rhs: Autopilotrpc_ModifyStatusRequest) -> Bool {
if lhs.enable != rhs.enable {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_ModifyStatusResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ModifyStatusResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_ModifyStatusResponse, rhs: Autopilotrpc_ModifyStatusResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_QueryScoresRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".QueryScoresRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pubkeys"),
2: .standard(proto: "ignore_local_state"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedStringField(value: &self.pubkeys)
case 2: try decoder.decodeSingularBoolField(value: &self.ignoreLocalState)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.pubkeys.isEmpty {
try visitor.visitRepeatedStringField(value: self.pubkeys, fieldNumber: 1)
}
if self.ignoreLocalState != false {
try visitor.visitSingularBoolField(value: self.ignoreLocalState, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_QueryScoresRequest, rhs: Autopilotrpc_QueryScoresRequest) -> Bool {
if lhs.pubkeys != rhs.pubkeys {return false}
if lhs.ignoreLocalState != rhs.ignoreLocalState {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_QueryScoresResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".QueryScoresResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "results"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedMessageField(value: &self.results)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.results.isEmpty {
try visitor.visitRepeatedMessageField(value: self.results, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_QueryScoresResponse, rhs: Autopilotrpc_QueryScoresResponse) -> Bool {
if lhs.results != rhs.results {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_QueryScoresResponse.HeuristicResult: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = Autopilotrpc_QueryScoresResponse.protoMessageName + ".HeuristicResult"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "heuristic"),
2: .same(proto: "scores"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.heuristic)
case 2: try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufString,SwiftProtobuf.ProtobufDouble>.self, value: &self.scores)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.heuristic.isEmpty {
try visitor.visitSingularStringField(value: self.heuristic, fieldNumber: 1)
}
if !self.scores.isEmpty {
try visitor.visitMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufString,SwiftProtobuf.ProtobufDouble>.self, value: self.scores, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_QueryScoresResponse.HeuristicResult, rhs: Autopilotrpc_QueryScoresResponse.HeuristicResult) -> Bool {
if lhs.heuristic != rhs.heuristic {return false}
if lhs.scores != rhs.scores {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_SetScoresRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SetScoresRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "heuristic"),
2: .same(proto: "scores"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.heuristic)
case 2: try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufString,SwiftProtobuf.ProtobufDouble>.self, value: &self.scores)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.heuristic.isEmpty {
try visitor.visitSingularStringField(value: self.heuristic, fieldNumber: 1)
}
if !self.scores.isEmpty {
try visitor.visitMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufString,SwiftProtobuf.ProtobufDouble>.self, value: self.scores, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_SetScoresRequest, rhs: Autopilotrpc_SetScoresRequest) -> Bool {
if lhs.heuristic != rhs.heuristic {return false}
if lhs.scores != rhs.scores {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Autopilotrpc_SetScoresResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SetScoresResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Autopilotrpc_SetScoresResponse, rhs: Autopilotrpc_SetScoresResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -0,0 +1,681 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: chainrpc/chainnotifier.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Chainrpc_ConfRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The transaction hash for which we should request a confirmation notification
///for. If set to a hash of all zeros, then the confirmation notification will
///be requested for the script instead.
var txid: Data = SwiftProtobuf.Internal.emptyData
///
///An output script within a transaction with the hash above which will be used
///by light clients to match block filters. If the transaction hash is set to a
///hash of all zeros, then a confirmation notification will be requested for
///this script instead.
var script: Data = SwiftProtobuf.Internal.emptyData
///
///The number of desired confirmations the transaction/output script should
///reach before dispatching a confirmation notification.
var numConfs: UInt32 = 0
///
///The earliest height in the chain for which the transaction/output script
///could have been included in a block. This should in most cases be set to the
///broadcast height of the transaction/output script.
var heightHint: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Chainrpc_ConfDetails {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The raw bytes of the confirmed transaction.
var rawTx: Data = SwiftProtobuf.Internal.emptyData
/// The hash of the block in which the confirmed transaction was included in.
var blockHash: Data = SwiftProtobuf.Internal.emptyData
/// The height of the block in which the confirmed transaction was included
/// in.
var blockHeight: UInt32 = 0
/// The index of the confirmed transaction within the transaction.
var txIndex: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
/// TODO(wilmer): need to know how the client will use this first.
struct Chainrpc_Reorg {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Chainrpc_ConfEvent {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var event: Chainrpc_ConfEvent.OneOf_Event? = nil
///
///An event that includes the confirmation details of the request
///(txid/ouput script).
var conf: Chainrpc_ConfDetails {
get {
if case .conf(let v)? = event {return v}
return Chainrpc_ConfDetails()
}
set {event = .conf(newValue)}
}
///
///An event send when the transaction of the request is reorged out of the
///chain.
var reorg: Chainrpc_Reorg {
get {
if case .reorg(let v)? = event {return v}
return Chainrpc_Reorg()
}
set {event = .reorg(newValue)}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum OneOf_Event: Equatable {
///
///An event that includes the confirmation details of the request
///(txid/ouput script).
case conf(Chainrpc_ConfDetails)
///
///An event send when the transaction of the request is reorged out of the
///chain.
case reorg(Chainrpc_Reorg)
#if !swift(>=4.1)
static func ==(lhs: Chainrpc_ConfEvent.OneOf_Event, rhs: Chainrpc_ConfEvent.OneOf_Event) -> Bool {
switch (lhs, rhs) {
case (.conf(let l), .conf(let r)): return l == r
case (.reorg(let l), .reorg(let r)): return l == r
default: return false
}
}
#endif
}
init() {}
}
struct Chainrpc_Outpoint {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The hash of the transaction.
var hash: Data = SwiftProtobuf.Internal.emptyData
/// The index of the output within the transaction.
var index: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Chainrpc_SpendRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The outpoint for which we should request a spend notification for. If set to
///a zero outpoint, then the spend notification will be requested for the
///script instead.
var outpoint: Chainrpc_Outpoint {
get {return _outpoint ?? Chainrpc_Outpoint()}
set {_outpoint = newValue}
}
/// Returns true if `outpoint` has been explicitly set.
var hasOutpoint: Bool {return self._outpoint != nil}
/// Clears the value of `outpoint`. Subsequent reads from it will return its default value.
mutating func clearOutpoint() {self._outpoint = nil}
///
///The output script for the outpoint above. This will be used by light clients
///to match block filters. If the outpoint is set to a zero outpoint, then a
///spend notification will be requested for this script instead.
var script: Data = SwiftProtobuf.Internal.emptyData
///
///The earliest height in the chain for which the outpoint/output script could
///have been spent. This should in most cases be set to the broadcast height of
///the outpoint/output script.
var heightHint: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _outpoint: Chainrpc_Outpoint? = nil
}
struct Chainrpc_SpendDetails {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The outpoint was that spent.
var spendingOutpoint: Chainrpc_Outpoint {
get {return _spendingOutpoint ?? Chainrpc_Outpoint()}
set {_spendingOutpoint = newValue}
}
/// Returns true if `spendingOutpoint` has been explicitly set.
var hasSpendingOutpoint: Bool {return self._spendingOutpoint != nil}
/// Clears the value of `spendingOutpoint`. Subsequent reads from it will return its default value.
mutating func clearSpendingOutpoint() {self._spendingOutpoint = nil}
/// The raw bytes of the spending transaction.
var rawSpendingTx: Data = SwiftProtobuf.Internal.emptyData
/// The hash of the spending transaction.
var spendingTxHash: Data = SwiftProtobuf.Internal.emptyData
/// The input of the spending transaction that fulfilled the spend request.
var spendingInputIndex: UInt32 = 0
/// The height at which the spending transaction was included in a block.
var spendingHeight: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _spendingOutpoint: Chainrpc_Outpoint? = nil
}
struct Chainrpc_SpendEvent {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var event: Chainrpc_SpendEvent.OneOf_Event? = nil
///
///An event that includes the details of the spending transaction of the
///request (outpoint/output script).
var spend: Chainrpc_SpendDetails {
get {
if case .spend(let v)? = event {return v}
return Chainrpc_SpendDetails()
}
set {event = .spend(newValue)}
}
///
///An event sent when the spending transaction of the request was
///reorged out of the chain.
var reorg: Chainrpc_Reorg {
get {
if case .reorg(let v)? = event {return v}
return Chainrpc_Reorg()
}
set {event = .reorg(newValue)}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum OneOf_Event: Equatable {
///
///An event that includes the details of the spending transaction of the
///request (outpoint/output script).
case spend(Chainrpc_SpendDetails)
///
///An event sent when the spending transaction of the request was
///reorged out of the chain.
case reorg(Chainrpc_Reorg)
#if !swift(>=4.1)
static func ==(lhs: Chainrpc_SpendEvent.OneOf_Event, rhs: Chainrpc_SpendEvent.OneOf_Event) -> Bool {
switch (lhs, rhs) {
case (.spend(let l), .spend(let r)): return l == r
case (.reorg(let l), .reorg(let r)): return l == r
default: return false
}
}
#endif
}
init() {}
}
struct Chainrpc_BlockEpoch {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The hash of the block.
var hash: Data = SwiftProtobuf.Internal.emptyData
/// The height of the block.
var height: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "chainrpc"
extension Chainrpc_ConfRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ConfRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "txid"),
2: .same(proto: "script"),
3: .standard(proto: "num_confs"),
4: .standard(proto: "height_hint"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.txid)
case 2: try decoder.decodeSingularBytesField(value: &self.script)
case 3: try decoder.decodeSingularUInt32Field(value: &self.numConfs)
case 4: try decoder.decodeSingularUInt32Field(value: &self.heightHint)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.txid.isEmpty {
try visitor.visitSingularBytesField(value: self.txid, fieldNumber: 1)
}
if !self.script.isEmpty {
try visitor.visitSingularBytesField(value: self.script, fieldNumber: 2)
}
if self.numConfs != 0 {
try visitor.visitSingularUInt32Field(value: self.numConfs, fieldNumber: 3)
}
if self.heightHint != 0 {
try visitor.visitSingularUInt32Field(value: self.heightHint, fieldNumber: 4)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_ConfRequest, rhs: Chainrpc_ConfRequest) -> Bool {
if lhs.txid != rhs.txid {return false}
if lhs.script != rhs.script {return false}
if lhs.numConfs != rhs.numConfs {return false}
if lhs.heightHint != rhs.heightHint {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_ConfDetails: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ConfDetails"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "raw_tx"),
2: .standard(proto: "block_hash"),
3: .standard(proto: "block_height"),
4: .standard(proto: "tx_index"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.rawTx)
case 2: try decoder.decodeSingularBytesField(value: &self.blockHash)
case 3: try decoder.decodeSingularUInt32Field(value: &self.blockHeight)
case 4: try decoder.decodeSingularUInt32Field(value: &self.txIndex)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.rawTx.isEmpty {
try visitor.visitSingularBytesField(value: self.rawTx, fieldNumber: 1)
}
if !self.blockHash.isEmpty {
try visitor.visitSingularBytesField(value: self.blockHash, fieldNumber: 2)
}
if self.blockHeight != 0 {
try visitor.visitSingularUInt32Field(value: self.blockHeight, fieldNumber: 3)
}
if self.txIndex != 0 {
try visitor.visitSingularUInt32Field(value: self.txIndex, fieldNumber: 4)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_ConfDetails, rhs: Chainrpc_ConfDetails) -> Bool {
if lhs.rawTx != rhs.rawTx {return false}
if lhs.blockHash != rhs.blockHash {return false}
if lhs.blockHeight != rhs.blockHeight {return false}
if lhs.txIndex != rhs.txIndex {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_Reorg: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Reorg"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_Reorg, rhs: Chainrpc_Reorg) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_ConfEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ConfEvent"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "conf"),
2: .same(proto: "reorg"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1:
var v: Chainrpc_ConfDetails?
if let current = self.event {
try decoder.handleConflictingOneOf()
if case .conf(let m) = current {v = m}
}
try decoder.decodeSingularMessageField(value: &v)
if let v = v {self.event = .conf(v)}
case 2:
var v: Chainrpc_Reorg?
if let current = self.event {
try decoder.handleConflictingOneOf()
if case .reorg(let m) = current {v = m}
}
try decoder.decodeSingularMessageField(value: &v)
if let v = v {self.event = .reorg(v)}
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
switch self.event {
case .conf(let v)?:
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
case .reorg(let v)?:
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
case nil: break
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_ConfEvent, rhs: Chainrpc_ConfEvent) -> Bool {
if lhs.event != rhs.event {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_Outpoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Outpoint"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "hash"),
2: .same(proto: "index"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.hash)
case 2: try decoder.decodeSingularUInt32Field(value: &self.index)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.hash.isEmpty {
try visitor.visitSingularBytesField(value: self.hash, fieldNumber: 1)
}
if self.index != 0 {
try visitor.visitSingularUInt32Field(value: self.index, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_Outpoint, rhs: Chainrpc_Outpoint) -> Bool {
if lhs.hash != rhs.hash {return false}
if lhs.index != rhs.index {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_SpendRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SpendRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "outpoint"),
2: .same(proto: "script"),
3: .standard(proto: "height_hint"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularMessageField(value: &self._outpoint)
case 2: try decoder.decodeSingularBytesField(value: &self.script)
case 3: try decoder.decodeSingularUInt32Field(value: &self.heightHint)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._outpoint {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
if !self.script.isEmpty {
try visitor.visitSingularBytesField(value: self.script, fieldNumber: 2)
}
if self.heightHint != 0 {
try visitor.visitSingularUInt32Field(value: self.heightHint, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_SpendRequest, rhs: Chainrpc_SpendRequest) -> Bool {
if lhs._outpoint != rhs._outpoint {return false}
if lhs.script != rhs.script {return false}
if lhs.heightHint != rhs.heightHint {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_SpendDetails: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SpendDetails"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "spending_outpoint"),
2: .standard(proto: "raw_spending_tx"),
3: .standard(proto: "spending_tx_hash"),
4: .standard(proto: "spending_input_index"),
5: .standard(proto: "spending_height"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularMessageField(value: &self._spendingOutpoint)
case 2: try decoder.decodeSingularBytesField(value: &self.rawSpendingTx)
case 3: try decoder.decodeSingularBytesField(value: &self.spendingTxHash)
case 4: try decoder.decodeSingularUInt32Field(value: &self.spendingInputIndex)
case 5: try decoder.decodeSingularUInt32Field(value: &self.spendingHeight)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._spendingOutpoint {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
if !self.rawSpendingTx.isEmpty {
try visitor.visitSingularBytesField(value: self.rawSpendingTx, fieldNumber: 2)
}
if !self.spendingTxHash.isEmpty {
try visitor.visitSingularBytesField(value: self.spendingTxHash, fieldNumber: 3)
}
if self.spendingInputIndex != 0 {
try visitor.visitSingularUInt32Field(value: self.spendingInputIndex, fieldNumber: 4)
}
if self.spendingHeight != 0 {
try visitor.visitSingularUInt32Field(value: self.spendingHeight, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_SpendDetails, rhs: Chainrpc_SpendDetails) -> Bool {
if lhs._spendingOutpoint != rhs._spendingOutpoint {return false}
if lhs.rawSpendingTx != rhs.rawSpendingTx {return false}
if lhs.spendingTxHash != rhs.spendingTxHash {return false}
if lhs.spendingInputIndex != rhs.spendingInputIndex {return false}
if lhs.spendingHeight != rhs.spendingHeight {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_SpendEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SpendEvent"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "spend"),
2: .same(proto: "reorg"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1:
var v: Chainrpc_SpendDetails?
if let current = self.event {
try decoder.handleConflictingOneOf()
if case .spend(let m) = current {v = m}
}
try decoder.decodeSingularMessageField(value: &v)
if let v = v {self.event = .spend(v)}
case 2:
var v: Chainrpc_Reorg?
if let current = self.event {
try decoder.handleConflictingOneOf()
if case .reorg(let m) = current {v = m}
}
try decoder.decodeSingularMessageField(value: &v)
if let v = v {self.event = .reorg(v)}
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
switch self.event {
case .spend(let v)?:
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
case .reorg(let v)?:
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
case nil: break
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_SpendEvent, rhs: Chainrpc_SpendEvent) -> Bool {
if lhs.event != rhs.event {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Chainrpc_BlockEpoch: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".BlockEpoch"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "hash"),
2: .same(proto: "height"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.hash)
case 2: try decoder.decodeSingularUInt32Field(value: &self.height)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.hash.isEmpty {
try visitor.visitSingularBytesField(value: self.hash, fieldNumber: 1)
}
if self.height != 0 {
try visitor.visitSingularUInt32Field(value: self.height, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Chainrpc_BlockEpoch, rhs: Chainrpc_BlockEpoch) -> Bool {
if lhs.hash != rhs.hash {return false}
if lhs.height != rhs.height {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -0,0 +1,393 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: invoicesrpc/invoices.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Invoicesrpc_CancelInvoiceMsg {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Hash corresponding to the (hold) invoice to cancel.
var paymentHash: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Invoicesrpc_CancelInvoiceResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Invoicesrpc_AddHoldInvoiceRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///An optional memo to attach along with the invoice. Used for record keeping
///purposes for the invoice's creator, and will also be set in the description
///field of the encoded payment request if the description_hash field is not
///being used.
var memo: String = String()
/// The hash of the preimage
var hash: Data = SwiftProtobuf.Internal.emptyData
///
///The value of this invoice in satoshis
///
///The fields value and value_msat are mutually exclusive.
var value: Int64 = 0
///
///The value of this invoice in millisatoshis
///
///The fields value and value_msat are mutually exclusive.
var valueMsat: Int64 = 0
///
///Hash (SHA-256) of a description of the payment. Used if the description of
///payment (memo) is too long to naturally fit within the description field
///of an encoded payment request.
var descriptionHash: Data = SwiftProtobuf.Internal.emptyData
/// Payment request expiry time in seconds. Default is 3600 (1 hour).
var expiry: Int64 = 0
/// Fallback on-chain address.
var fallbackAddr: String = String()
/// Delta to use for the time-lock of the CLTV extended to the final hop.
var cltvExpiry: UInt64 = 0
///
///Route hints that can each be individually used to assist in reaching the
///invoice's destination.
var routeHints: [Lnrpc_RouteHint] = []
/// Whether this invoice should include routing hints for private channels.
var `private`: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Invoicesrpc_AddHoldInvoiceResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///A bare-bones invoice for a payment within the Lightning Network. With the
///details of the invoice, the sender has all the data necessary to send a
///payment to the recipient.
var paymentRequest: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Invoicesrpc_SettleInvoiceMsg {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Externally discovered pre-image that should be used to settle the hold
/// invoice.
var preimage: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Invoicesrpc_SettleInvoiceResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Invoicesrpc_SubscribeSingleInvoiceRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Hash corresponding to the (hold) invoice to subscribe to.
var rHash: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "invoicesrpc"
extension Invoicesrpc_CancelInvoiceMsg: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".CancelInvoiceMsg"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "payment_hash"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.paymentHash)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.paymentHash.isEmpty {
try visitor.visitSingularBytesField(value: self.paymentHash, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_CancelInvoiceMsg, rhs: Invoicesrpc_CancelInvoiceMsg) -> Bool {
if lhs.paymentHash != rhs.paymentHash {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Invoicesrpc_CancelInvoiceResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".CancelInvoiceResp"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_CancelInvoiceResp, rhs: Invoicesrpc_CancelInvoiceResp) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Invoicesrpc_AddHoldInvoiceRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".AddHoldInvoiceRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "memo"),
2: .same(proto: "hash"),
3: .same(proto: "value"),
10: .standard(proto: "value_msat"),
4: .standard(proto: "description_hash"),
5: .same(proto: "expiry"),
6: .standard(proto: "fallback_addr"),
7: .standard(proto: "cltv_expiry"),
8: .standard(proto: "route_hints"),
9: .same(proto: "private"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.memo)
case 2: try decoder.decodeSingularBytesField(value: &self.hash)
case 3: try decoder.decodeSingularInt64Field(value: &self.value)
case 4: try decoder.decodeSingularBytesField(value: &self.descriptionHash)
case 5: try decoder.decodeSingularInt64Field(value: &self.expiry)
case 6: try decoder.decodeSingularStringField(value: &self.fallbackAddr)
case 7: try decoder.decodeSingularUInt64Field(value: &self.cltvExpiry)
case 8: try decoder.decodeRepeatedMessageField(value: &self.routeHints)
case 9: try decoder.decodeSingularBoolField(value: &self.`private`)
case 10: try decoder.decodeSingularInt64Field(value: &self.valueMsat)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.memo.isEmpty {
try visitor.visitSingularStringField(value: self.memo, fieldNumber: 1)
}
if !self.hash.isEmpty {
try visitor.visitSingularBytesField(value: self.hash, fieldNumber: 2)
}
if self.value != 0 {
try visitor.visitSingularInt64Field(value: self.value, fieldNumber: 3)
}
if !self.descriptionHash.isEmpty {
try visitor.visitSingularBytesField(value: self.descriptionHash, fieldNumber: 4)
}
if self.expiry != 0 {
try visitor.visitSingularInt64Field(value: self.expiry, fieldNumber: 5)
}
if !self.fallbackAddr.isEmpty {
try visitor.visitSingularStringField(value: self.fallbackAddr, fieldNumber: 6)
}
if self.cltvExpiry != 0 {
try visitor.visitSingularUInt64Field(value: self.cltvExpiry, fieldNumber: 7)
}
if !self.routeHints.isEmpty {
try visitor.visitRepeatedMessageField(value: self.routeHints, fieldNumber: 8)
}
if self.`private` != false {
try visitor.visitSingularBoolField(value: self.`private`, fieldNumber: 9)
}
if self.valueMsat != 0 {
try visitor.visitSingularInt64Field(value: self.valueMsat, fieldNumber: 10)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_AddHoldInvoiceRequest, rhs: Invoicesrpc_AddHoldInvoiceRequest) -> Bool {
if lhs.memo != rhs.memo {return false}
if lhs.hash != rhs.hash {return false}
if lhs.value != rhs.value {return false}
if lhs.valueMsat != rhs.valueMsat {return false}
if lhs.descriptionHash != rhs.descriptionHash {return false}
if lhs.expiry != rhs.expiry {return false}
if lhs.fallbackAddr != rhs.fallbackAddr {return false}
if lhs.cltvExpiry != rhs.cltvExpiry {return false}
if lhs.routeHints != rhs.routeHints {return false}
if lhs.`private` != rhs.`private` {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Invoicesrpc_AddHoldInvoiceResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".AddHoldInvoiceResp"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "payment_request"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.paymentRequest)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.paymentRequest.isEmpty {
try visitor.visitSingularStringField(value: self.paymentRequest, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_AddHoldInvoiceResp, rhs: Invoicesrpc_AddHoldInvoiceResp) -> Bool {
if lhs.paymentRequest != rhs.paymentRequest {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Invoicesrpc_SettleInvoiceMsg: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SettleInvoiceMsg"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "preimage"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.preimage)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.preimage.isEmpty {
try visitor.visitSingularBytesField(value: self.preimage, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_SettleInvoiceMsg, rhs: Invoicesrpc_SettleInvoiceMsg) -> Bool {
if lhs.preimage != rhs.preimage {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Invoicesrpc_SettleInvoiceResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SettleInvoiceResp"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_SettleInvoiceResp, rhs: Invoicesrpc_SettleInvoiceResp) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Invoicesrpc_SubscribeSingleInvoiceRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SubscribeSingleInvoiceRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
2: .standard(proto: "r_hash"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 2: try decoder.decodeSingularBytesField(value: &self.rHash)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.rHash.isEmpty {
try visitor.visitSingularBytesField(value: self.rHash, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Invoicesrpc_SubscribeSingleInvoiceRequest, rhs: Invoicesrpc_SubscribeSingleInvoiceRequest) -> Bool {
if lhs.rHash != rhs.rHash {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -0,0 +1,93 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: lnclipb/lncli.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Lnclipb_VersionResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The version information for lncli.
var lncli: Verrpc_Version {
get {return _lncli ?? Verrpc_Version()}
set {_lncli = newValue}
}
/// Returns true if `lncli` has been explicitly set.
var hasLncli: Bool {return self._lncli != nil}
/// Clears the value of `lncli`. Subsequent reads from it will return its default value.
mutating func clearLncli() {self._lncli = nil}
/// The version information for lnd.
var lnd: Verrpc_Version {
get {return _lnd ?? Verrpc_Version()}
set {_lnd = newValue}
}
/// Returns true if `lnd` has been explicitly set.
var hasLnd: Bool {return self._lnd != nil}
/// Clears the value of `lnd`. Subsequent reads from it will return its default value.
mutating func clearLnd() {self._lnd = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _lncli: Verrpc_Version? = nil
fileprivate var _lnd: Verrpc_Version? = nil
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "lnclipb"
extension Lnclipb_VersionResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".VersionResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "lncli"),
2: .same(proto: "lnd"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularMessageField(value: &self._lncli)
case 2: try decoder.decodeSingularMessageField(value: &self._lnd)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._lncli {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
if let v = self._lnd {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnclipb_VersionResponse, rhs: Lnclipb_VersionResponse) -> Bool {
if lhs._lncli != rhs._lncli {return false}
if lhs._lnd != rhs._lnd {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,833 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: signrpc/signer.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Signrpc_KeyLocator {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The family of key being identified.
var keyFamily: Int32 = 0
/// The precise index of the key being identified.
var keyIndex: Int32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_KeyDescriptor {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The raw bytes of the key being identified. Either this or the KeyLocator
///must be specified.
var rawKeyBytes: Data = SwiftProtobuf.Internal.emptyData
///
///The key locator that identifies which key to use for signing. Either this
///or the raw bytes of the target key must be specified.
var keyLoc: Signrpc_KeyLocator {
get {return _keyLoc ?? Signrpc_KeyLocator()}
set {_keyLoc = newValue}
}
/// Returns true if `keyLoc` has been explicitly set.
var hasKeyLoc: Bool {return self._keyLoc != nil}
/// Clears the value of `keyLoc`. Subsequent reads from it will return its default value.
mutating func clearKeyLoc() {self._keyLoc = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _keyLoc: Signrpc_KeyLocator? = nil
}
struct Signrpc_TxOut {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The value of the output being spent.
var value: Int64 = 0
/// The script of the output being spent.
var pkScript: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_SignDescriptor {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///A descriptor that precisely describes *which* key to use for signing. This
///may provide the raw public key directly, or require the Signer to re-derive
///the key according to the populated derivation path.
///
///Note that if the key descriptor was obtained through walletrpc.DeriveKey,
///then the key locator MUST always be provided, since the derived keys are not
///persisted unlike with DeriveNextKey.
var keyDesc: Signrpc_KeyDescriptor {
get {return _keyDesc ?? Signrpc_KeyDescriptor()}
set {_keyDesc = newValue}
}
/// Returns true if `keyDesc` has been explicitly set.
var hasKeyDesc: Bool {return self._keyDesc != nil}
/// Clears the value of `keyDesc`. Subsequent reads from it will return its default value.
mutating func clearKeyDesc() {self._keyDesc = nil}
///
///A scalar value that will be added to the private key corresponding to the
///above public key to obtain the private key to be used to sign this input.
///This value is typically derived via the following computation:
///
/// derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
var singleTweak: Data = SwiftProtobuf.Internal.emptyData
///
///A private key that will be used in combination with its corresponding
///private key to derive the private key that is to be used to sign the target
///input. Within the Lightning protocol, this value is typically the
///commitment secret from a previously revoked commitment transaction. This
///value is in combination with two hash values, and the original private key
///to derive the private key to be used when signing.
///
/// k = (privKey*sha256(pubKey || tweakPub) +
///tweakPriv*sha256(tweakPub || pubKey)) mod N
var doubleTweak: Data = SwiftProtobuf.Internal.emptyData
///
///The full script required to properly redeem the output. This field will
///only be populated if a p2wsh or a p2sh output is being signed.
var witnessScript: Data = SwiftProtobuf.Internal.emptyData
///
///A description of the output being spent. The value and script MUST be
///provided.
var output: Signrpc_TxOut {
get {return _output ?? Signrpc_TxOut()}
set {_output = newValue}
}
/// Returns true if `output` has been explicitly set.
var hasOutput: Bool {return self._output != nil}
/// Clears the value of `output`. Subsequent reads from it will return its default value.
mutating func clearOutput() {self._output = nil}
///
///The target sighash type that should be used when generating the final
///sighash, and signature.
var sighash: UInt32 = 0
///
///The target input within the transaction that should be signed.
var inputIndex: Int32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _keyDesc: Signrpc_KeyDescriptor? = nil
fileprivate var _output: Signrpc_TxOut? = nil
}
struct Signrpc_SignReq {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The raw bytes of the transaction to be signed.
var rawTxBytes: Data = SwiftProtobuf.Internal.emptyData
/// A set of sign descriptors, for each input to be signed.
var signDescs: [Signrpc_SignDescriptor] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_SignResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///A set of signatures realized in a fixed 64-byte format ordered in ascending
///input order.
var rawSigs: [Data] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_InputScript {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The serializes witness stack for the specified input.
var witness: [Data] = []
///
///The optional sig script for the specified witness that will only be set if
///the input specified is a nested p2sh witness program.
var sigScript: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_InputScriptResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The set of fully valid input scripts requested.
var inputScripts: [Signrpc_InputScript] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_SignMessageReq {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The message to be signed.
var msg: Data = SwiftProtobuf.Internal.emptyData
/// The key locator that identifies which key to use for signing.
var keyLoc: Signrpc_KeyLocator {
get {return _keyLoc ?? Signrpc_KeyLocator()}
set {_keyLoc = newValue}
}
/// Returns true if `keyLoc` has been explicitly set.
var hasKeyLoc: Bool {return self._keyLoc != nil}
/// Clears the value of `keyLoc`. Subsequent reads from it will return its default value.
mutating func clearKeyLoc() {self._keyLoc = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _keyLoc: Signrpc_KeyLocator? = nil
}
struct Signrpc_SignMessageResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The signature for the given message in the fixed-size LN wire format.
var signature: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_VerifyMessageReq {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The message over which the signature is to be verified.
var msg: Data = SwiftProtobuf.Internal.emptyData
///
///The fixed-size LN wire encoded signature to be verified over the given
///message.
var signature: Data = SwiftProtobuf.Internal.emptyData
/// The public key the signature has to be valid for.
var pubkey: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_VerifyMessageResp {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Whether the signature was valid over the given message.
var valid: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Signrpc_SharedKeyRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The ephemeral public key to use for the DH key derivation.
var ephemeralPubkey: Data = SwiftProtobuf.Internal.emptyData
///
///The optional key locator of the local key that should be used. If this
///parameter is not set then the node's identity private key will be used.
var keyLoc: Signrpc_KeyLocator {
get {return _keyLoc ?? Signrpc_KeyLocator()}
set {_keyLoc = newValue}
}
/// Returns true if `keyLoc` has been explicitly set.
var hasKeyLoc: Bool {return self._keyLoc != nil}
/// Clears the value of `keyLoc`. Subsequent reads from it will return its default value.
mutating func clearKeyLoc() {self._keyLoc = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _keyLoc: Signrpc_KeyLocator? = nil
}
struct Signrpc_SharedKeyResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The shared public key, hashed with sha256.
var sharedKey: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "signrpc"
extension Signrpc_KeyLocator: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".KeyLocator"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "key_family"),
2: .standard(proto: "key_index"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularInt32Field(value: &self.keyFamily)
case 2: try decoder.decodeSingularInt32Field(value: &self.keyIndex)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.keyFamily != 0 {
try visitor.visitSingularInt32Field(value: self.keyFamily, fieldNumber: 1)
}
if self.keyIndex != 0 {
try visitor.visitSingularInt32Field(value: self.keyIndex, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_KeyLocator, rhs: Signrpc_KeyLocator) -> Bool {
if lhs.keyFamily != rhs.keyFamily {return false}
if lhs.keyIndex != rhs.keyIndex {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_KeyDescriptor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".KeyDescriptor"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "raw_key_bytes"),
2: .standard(proto: "key_loc"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.rawKeyBytes)
case 2: try decoder.decodeSingularMessageField(value: &self._keyLoc)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.rawKeyBytes.isEmpty {
try visitor.visitSingularBytesField(value: self.rawKeyBytes, fieldNumber: 1)
}
if let v = self._keyLoc {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_KeyDescriptor, rhs: Signrpc_KeyDescriptor) -> Bool {
if lhs.rawKeyBytes != rhs.rawKeyBytes {return false}
if lhs._keyLoc != rhs._keyLoc {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_TxOut: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TxOut"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "value"),
2: .standard(proto: "pk_script"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularInt64Field(value: &self.value)
case 2: try decoder.decodeSingularBytesField(value: &self.pkScript)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.value != 0 {
try visitor.visitSingularInt64Field(value: self.value, fieldNumber: 1)
}
if !self.pkScript.isEmpty {
try visitor.visitSingularBytesField(value: self.pkScript, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_TxOut, rhs: Signrpc_TxOut) -> Bool {
if lhs.value != rhs.value {return false}
if lhs.pkScript != rhs.pkScript {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SignDescriptor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SignDescriptor"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "key_desc"),
2: .standard(proto: "single_tweak"),
3: .standard(proto: "double_tweak"),
4: .standard(proto: "witness_script"),
5: .same(proto: "output"),
7: .same(proto: "sighash"),
8: .standard(proto: "input_index"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularMessageField(value: &self._keyDesc)
case 2: try decoder.decodeSingularBytesField(value: &self.singleTweak)
case 3: try decoder.decodeSingularBytesField(value: &self.doubleTweak)
case 4: try decoder.decodeSingularBytesField(value: &self.witnessScript)
case 5: try decoder.decodeSingularMessageField(value: &self._output)
case 7: try decoder.decodeSingularUInt32Field(value: &self.sighash)
case 8: try decoder.decodeSingularInt32Field(value: &self.inputIndex)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._keyDesc {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
if !self.singleTweak.isEmpty {
try visitor.visitSingularBytesField(value: self.singleTweak, fieldNumber: 2)
}
if !self.doubleTweak.isEmpty {
try visitor.visitSingularBytesField(value: self.doubleTweak, fieldNumber: 3)
}
if !self.witnessScript.isEmpty {
try visitor.visitSingularBytesField(value: self.witnessScript, fieldNumber: 4)
}
if let v = self._output {
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
}
if self.sighash != 0 {
try visitor.visitSingularUInt32Field(value: self.sighash, fieldNumber: 7)
}
if self.inputIndex != 0 {
try visitor.visitSingularInt32Field(value: self.inputIndex, fieldNumber: 8)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SignDescriptor, rhs: Signrpc_SignDescriptor) -> Bool {
if lhs._keyDesc != rhs._keyDesc {return false}
if lhs.singleTweak != rhs.singleTweak {return false}
if lhs.doubleTweak != rhs.doubleTweak {return false}
if lhs.witnessScript != rhs.witnessScript {return false}
if lhs._output != rhs._output {return false}
if lhs.sighash != rhs.sighash {return false}
if lhs.inputIndex != rhs.inputIndex {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SignReq: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SignReq"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "raw_tx_bytes"),
2: .standard(proto: "sign_descs"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.rawTxBytes)
case 2: try decoder.decodeRepeatedMessageField(value: &self.signDescs)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.rawTxBytes.isEmpty {
try visitor.visitSingularBytesField(value: self.rawTxBytes, fieldNumber: 1)
}
if !self.signDescs.isEmpty {
try visitor.visitRepeatedMessageField(value: self.signDescs, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SignReq, rhs: Signrpc_SignReq) -> Bool {
if lhs.rawTxBytes != rhs.rawTxBytes {return false}
if lhs.signDescs != rhs.signDescs {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SignResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SignResp"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "raw_sigs"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedBytesField(value: &self.rawSigs)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.rawSigs.isEmpty {
try visitor.visitRepeatedBytesField(value: self.rawSigs, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SignResp, rhs: Signrpc_SignResp) -> Bool {
if lhs.rawSigs != rhs.rawSigs {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_InputScript: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".InputScript"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "witness"),
2: .standard(proto: "sig_script"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedBytesField(value: &self.witness)
case 2: try decoder.decodeSingularBytesField(value: &self.sigScript)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.witness.isEmpty {
try visitor.visitRepeatedBytesField(value: self.witness, fieldNumber: 1)
}
if !self.sigScript.isEmpty {
try visitor.visitSingularBytesField(value: self.sigScript, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_InputScript, rhs: Signrpc_InputScript) -> Bool {
if lhs.witness != rhs.witness {return false}
if lhs.sigScript != rhs.sigScript {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_InputScriptResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".InputScriptResp"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "input_scripts"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedMessageField(value: &self.inputScripts)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.inputScripts.isEmpty {
try visitor.visitRepeatedMessageField(value: self.inputScripts, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_InputScriptResp, rhs: Signrpc_InputScriptResp) -> Bool {
if lhs.inputScripts != rhs.inputScripts {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SignMessageReq: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SignMessageReq"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "msg"),
2: .standard(proto: "key_loc"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.msg)
case 2: try decoder.decodeSingularMessageField(value: &self._keyLoc)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.msg.isEmpty {
try visitor.visitSingularBytesField(value: self.msg, fieldNumber: 1)
}
if let v = self._keyLoc {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SignMessageReq, rhs: Signrpc_SignMessageReq) -> Bool {
if lhs.msg != rhs.msg {return false}
if lhs._keyLoc != rhs._keyLoc {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SignMessageResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SignMessageResp"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "signature"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.signature)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.signature.isEmpty {
try visitor.visitSingularBytesField(value: self.signature, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SignMessageResp, rhs: Signrpc_SignMessageResp) -> Bool {
if lhs.signature != rhs.signature {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_VerifyMessageReq: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".VerifyMessageReq"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "msg"),
2: .same(proto: "signature"),
3: .same(proto: "pubkey"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.msg)
case 2: try decoder.decodeSingularBytesField(value: &self.signature)
case 3: try decoder.decodeSingularBytesField(value: &self.pubkey)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.msg.isEmpty {
try visitor.visitSingularBytesField(value: self.msg, fieldNumber: 1)
}
if !self.signature.isEmpty {
try visitor.visitSingularBytesField(value: self.signature, fieldNumber: 2)
}
if !self.pubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.pubkey, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_VerifyMessageReq, rhs: Signrpc_VerifyMessageReq) -> Bool {
if lhs.msg != rhs.msg {return false}
if lhs.signature != rhs.signature {return false}
if lhs.pubkey != rhs.pubkey {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_VerifyMessageResp: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".VerifyMessageResp"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "valid"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBoolField(value: &self.valid)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.valid != false {
try visitor.visitSingularBoolField(value: self.valid, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_VerifyMessageResp, rhs: Signrpc_VerifyMessageResp) -> Bool {
if lhs.valid != rhs.valid {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SharedKeyRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SharedKeyRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "ephemeral_pubkey"),
2: .standard(proto: "key_loc"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.ephemeralPubkey)
case 2: try decoder.decodeSingularMessageField(value: &self._keyLoc)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.ephemeralPubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.ephemeralPubkey, fieldNumber: 1)
}
if let v = self._keyLoc {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SharedKeyRequest, rhs: Signrpc_SharedKeyRequest) -> Bool {
if lhs.ephemeralPubkey != rhs.ephemeralPubkey {return false}
if lhs._keyLoc != rhs._keyLoc {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Signrpc_SharedKeyResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SharedKeyResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "shared_key"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.sharedKey)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.sharedKey.isEmpty {
try visitor.visitSingularBytesField(value: self.sharedKey, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Signrpc_SharedKeyResponse, rhs: Signrpc_SharedKeyResponse) -> Bool {
if lhs.sharedKey != rhs.sharedKey {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -0,0 +1,168 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: verrpc/verrpc.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Verrpc_VersionRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Verrpc_Version {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// A verbose description of the daemon's commit.
var commit: String = String()
/// The SHA1 commit hash that the daemon is compiled with.
var commitHash: String = String()
/// The semantic version.
var version: String = String()
/// The major application version.
var appMajor: UInt32 = 0
/// The minor application version.
var appMinor: UInt32 = 0
/// The application patch number.
var appPatch: UInt32 = 0
/// The application pre-release modifier, possibly empty.
var appPreRelease: String = String()
/// The list of build tags that were supplied during compilation.
var buildTags: [String] = []
/// The version of go that compiled the executable.
var goVersion: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "verrpc"
extension Verrpc_VersionRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".VersionRequest"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Verrpc_VersionRequest, rhs: Verrpc_VersionRequest) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Verrpc_Version: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Version"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "commit"),
2: .standard(proto: "commit_hash"),
3: .same(proto: "version"),
4: .standard(proto: "app_major"),
5: .standard(proto: "app_minor"),
6: .standard(proto: "app_patch"),
7: .standard(proto: "app_pre_release"),
8: .standard(proto: "build_tags"),
9: .standard(proto: "go_version"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.commit)
case 2: try decoder.decodeSingularStringField(value: &self.commitHash)
case 3: try decoder.decodeSingularStringField(value: &self.version)
case 4: try decoder.decodeSingularUInt32Field(value: &self.appMajor)
case 5: try decoder.decodeSingularUInt32Field(value: &self.appMinor)
case 6: try decoder.decodeSingularUInt32Field(value: &self.appPatch)
case 7: try decoder.decodeSingularStringField(value: &self.appPreRelease)
case 8: try decoder.decodeRepeatedStringField(value: &self.buildTags)
case 9: try decoder.decodeSingularStringField(value: &self.goVersion)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.commit.isEmpty {
try visitor.visitSingularStringField(value: self.commit, fieldNumber: 1)
}
if !self.commitHash.isEmpty {
try visitor.visitSingularStringField(value: self.commitHash, fieldNumber: 2)
}
if !self.version.isEmpty {
try visitor.visitSingularStringField(value: self.version, fieldNumber: 3)
}
if self.appMajor != 0 {
try visitor.visitSingularUInt32Field(value: self.appMajor, fieldNumber: 4)
}
if self.appMinor != 0 {
try visitor.visitSingularUInt32Field(value: self.appMinor, fieldNumber: 5)
}
if self.appPatch != 0 {
try visitor.visitSingularUInt32Field(value: self.appPatch, fieldNumber: 6)
}
if !self.appPreRelease.isEmpty {
try visitor.visitSingularStringField(value: self.appPreRelease, fieldNumber: 7)
}
if !self.buildTags.isEmpty {
try visitor.visitRepeatedStringField(value: self.buildTags, fieldNumber: 8)
}
if !self.goVersion.isEmpty {
try visitor.visitSingularStringField(value: self.goVersion, fieldNumber: 9)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Verrpc_Version, rhs: Verrpc_Version) -> Bool {
if lhs.commit != rhs.commit {return false}
if lhs.commitHash != rhs.commitHash {return false}
if lhs.version != rhs.version {return false}
if lhs.appMajor != rhs.appMajor {return false}
if lhs.appMinor != rhs.appMinor {return false}
if lhs.appPatch != rhs.appPatch {return false}
if lhs.appPreRelease != rhs.appPreRelease {return false}
if lhs.buildTags != rhs.buildTags {return false}
if lhs.goVersion != rhs.goVersion {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,473 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: walletunlocker.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Lnrpc_GenSeedRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///aezeed_passphrase is an optional user provided passphrase that will be used
///to encrypt the generated aezeed cipher seed. When using REST, this field
///must be encoded as base64.
var aezeedPassphrase: Data = SwiftProtobuf.Internal.emptyData
///
///seed_entropy is an optional 16-bytes generated via CSPRNG. If not
///specified, then a fresh set of randomness will be used to create the seed.
///When using REST, this field must be encoded as base64.
var seedEntropy: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Lnrpc_GenSeedResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed
///cipher seed obtained by the user. This field is optional, as if not
///provided, then the daemon will generate a new cipher seed for the user.
///Otherwise, then the daemon will attempt to recover the wallet state linked
///to this cipher seed.
var cipherSeedMnemonic: [String] = []
///
///enciphered_seed are the raw aezeed cipher seed bytes. This is the raw
///cipher text before run through our mnemonic encoding scheme.
var encipheredSeed: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Lnrpc_InitWalletRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///wallet_password is the passphrase that should be used to encrypt the
///wallet. This MUST be at least 8 chars in length. After creation, this
///password is required to unlock the daemon. When using REST, this field
///must be encoded as base64.
var walletPassword: Data = SwiftProtobuf.Internal.emptyData
///
///cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed
///cipher seed obtained by the user. This may have been generated by the
///GenSeed method, or be an existing seed.
var cipherSeedMnemonic: [String] = []
///
///aezeed_passphrase is an optional user provided passphrase that will be used
///to encrypt the generated aezeed cipher seed. When using REST, this field
///must be encoded as base64.
var aezeedPassphrase: Data = SwiftProtobuf.Internal.emptyData
///
///recovery_window is an optional argument specifying the address lookahead
///when restoring a wallet seed. The recovery window applies to each
///individual branch of the BIP44 derivation paths. Supplying a recovery
///window of zero indicates that no addresses should be recovered, such after
///the first initialization of the wallet.
var recoveryWindow: Int32 = 0
///
///channel_backups is an optional argument that allows clients to recover the
///settled funds within a set of channels. This should be populated if the
///user was unable to close out all channels and sweep funds before partial or
///total data loss occurred. If specified, then after on-chain recovery of
///funds, lnd begin to carry out the data loss recovery protocol in order to
///recover the funds in each channel from a remote force closed transaction.
var channelBackups: Lnrpc_ChanBackupSnapshot {
get {return _channelBackups ?? Lnrpc_ChanBackupSnapshot()}
set {_channelBackups = newValue}
}
/// Returns true if `channelBackups` has been explicitly set.
var hasChannelBackups: Bool {return self._channelBackups != nil}
/// Clears the value of `channelBackups`. Subsequent reads from it will return its default value.
mutating func clearChannelBackups() {self._channelBackups = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _channelBackups: Lnrpc_ChanBackupSnapshot? = nil
}
struct Lnrpc_InitWalletResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Lnrpc_UnlockWalletRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///wallet_password should be the current valid passphrase for the daemon. This
///will be required to decrypt on-disk material that the daemon requires to
///function properly. When using REST, this field must be encoded as base64.
var walletPassword: Data = SwiftProtobuf.Internal.emptyData
///
///recovery_window is an optional argument specifying the address lookahead
///when restoring a wallet seed. The recovery window applies to each
///individual branch of the BIP44 derivation paths. Supplying a recovery
///window of zero indicates that no addresses should be recovered, such after
///the first initialization of the wallet.
var recoveryWindow: Int32 = 0
///
///channel_backups is an optional argument that allows clients to recover the
///settled funds within a set of channels. This should be populated if the
///user was unable to close out all channels and sweep funds before partial or
///total data loss occurred. If specified, then after on-chain recovery of
///funds, lnd begin to carry out the data loss recovery protocol in order to
///recover the funds in each channel from a remote force closed transaction.
var channelBackups: Lnrpc_ChanBackupSnapshot {
get {return _channelBackups ?? Lnrpc_ChanBackupSnapshot()}
set {_channelBackups = newValue}
}
/// Returns true if `channelBackups` has been explicitly set.
var hasChannelBackups: Bool {return self._channelBackups != nil}
/// Clears the value of `channelBackups`. Subsequent reads from it will return its default value.
mutating func clearChannelBackups() {self._channelBackups = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _channelBackups: Lnrpc_ChanBackupSnapshot? = nil
}
struct Lnrpc_UnlockWalletResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Lnrpc_ChangePasswordRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///current_password should be the current valid passphrase used to unlock the
///daemon. When using REST, this field must be encoded as base64.
var currentPassword: Data = SwiftProtobuf.Internal.emptyData
///
///new_password should be the new passphrase that will be needed to unlock the
///daemon. When using REST, this field must be encoded as base64.
var newPassword: Data = SwiftProtobuf.Internal.emptyData
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Lnrpc_ChangePasswordResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "lnrpc"
extension Lnrpc_GenSeedRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GenSeedRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "aezeed_passphrase"),
2: .standard(proto: "seed_entropy"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.aezeedPassphrase)
case 2: try decoder.decodeSingularBytesField(value: &self.seedEntropy)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.aezeedPassphrase.isEmpty {
try visitor.visitSingularBytesField(value: self.aezeedPassphrase, fieldNumber: 1)
}
if !self.seedEntropy.isEmpty {
try visitor.visitSingularBytesField(value: self.seedEntropy, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_GenSeedRequest, rhs: Lnrpc_GenSeedRequest) -> Bool {
if lhs.aezeedPassphrase != rhs.aezeedPassphrase {return false}
if lhs.seedEntropy != rhs.seedEntropy {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_GenSeedResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GenSeedResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "cipher_seed_mnemonic"),
2: .standard(proto: "enciphered_seed"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedStringField(value: &self.cipherSeedMnemonic)
case 2: try decoder.decodeSingularBytesField(value: &self.encipheredSeed)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.cipherSeedMnemonic.isEmpty {
try visitor.visitRepeatedStringField(value: self.cipherSeedMnemonic, fieldNumber: 1)
}
if !self.encipheredSeed.isEmpty {
try visitor.visitSingularBytesField(value: self.encipheredSeed, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_GenSeedResponse, rhs: Lnrpc_GenSeedResponse) -> Bool {
if lhs.cipherSeedMnemonic != rhs.cipherSeedMnemonic {return false}
if lhs.encipheredSeed != rhs.encipheredSeed {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_InitWalletRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".InitWalletRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "wallet_password"),
2: .standard(proto: "cipher_seed_mnemonic"),
3: .standard(proto: "aezeed_passphrase"),
4: .standard(proto: "recovery_window"),
5: .standard(proto: "channel_backups"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.walletPassword)
case 2: try decoder.decodeRepeatedStringField(value: &self.cipherSeedMnemonic)
case 3: try decoder.decodeSingularBytesField(value: &self.aezeedPassphrase)
case 4: try decoder.decodeSingularInt32Field(value: &self.recoveryWindow)
case 5: try decoder.decodeSingularMessageField(value: &self._channelBackups)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.walletPassword.isEmpty {
try visitor.visitSingularBytesField(value: self.walletPassword, fieldNumber: 1)
}
if !self.cipherSeedMnemonic.isEmpty {
try visitor.visitRepeatedStringField(value: self.cipherSeedMnemonic, fieldNumber: 2)
}
if !self.aezeedPassphrase.isEmpty {
try visitor.visitSingularBytesField(value: self.aezeedPassphrase, fieldNumber: 3)
}
if self.recoveryWindow != 0 {
try visitor.visitSingularInt32Field(value: self.recoveryWindow, fieldNumber: 4)
}
if let v = self._channelBackups {
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_InitWalletRequest, rhs: Lnrpc_InitWalletRequest) -> Bool {
if lhs.walletPassword != rhs.walletPassword {return false}
if lhs.cipherSeedMnemonic != rhs.cipherSeedMnemonic {return false}
if lhs.aezeedPassphrase != rhs.aezeedPassphrase {return false}
if lhs.recoveryWindow != rhs.recoveryWindow {return false}
if lhs._channelBackups != rhs._channelBackups {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_InitWalletResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".InitWalletResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_InitWalletResponse, rhs: Lnrpc_InitWalletResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_UnlockWalletRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".UnlockWalletRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "wallet_password"),
2: .standard(proto: "recovery_window"),
3: .standard(proto: "channel_backups"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.walletPassword)
case 2: try decoder.decodeSingularInt32Field(value: &self.recoveryWindow)
case 3: try decoder.decodeSingularMessageField(value: &self._channelBackups)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.walletPassword.isEmpty {
try visitor.visitSingularBytesField(value: self.walletPassword, fieldNumber: 1)
}
if self.recoveryWindow != 0 {
try visitor.visitSingularInt32Field(value: self.recoveryWindow, fieldNumber: 2)
}
if let v = self._channelBackups {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_UnlockWalletRequest, rhs: Lnrpc_UnlockWalletRequest) -> Bool {
if lhs.walletPassword != rhs.walletPassword {return false}
if lhs.recoveryWindow != rhs.recoveryWindow {return false}
if lhs._channelBackups != rhs._channelBackups {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_UnlockWalletResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".UnlockWalletResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_UnlockWalletResponse, rhs: Lnrpc_UnlockWalletResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_ChangePasswordRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ChangePasswordRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "current_password"),
2: .standard(proto: "new_password"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.currentPassword)
case 2: try decoder.decodeSingularBytesField(value: &self.newPassword)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.currentPassword.isEmpty {
try visitor.visitSingularBytesField(value: self.currentPassword, fieldNumber: 1)
}
if !self.newPassword.isEmpty {
try visitor.visitSingularBytesField(value: self.newPassword, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_ChangePasswordRequest, rhs: Lnrpc_ChangePasswordRequest) -> Bool {
if lhs.currentPassword != rhs.currentPassword {return false}
if lhs.newPassword != rhs.newPassword {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Lnrpc_ChangePasswordResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ChangePasswordResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Lnrpc_ChangePasswordResponse, rhs: Lnrpc_ChangePasswordResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -0,0 +1,114 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: watchtowerrpc/watchtower.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Watchtowerrpc_GetInfoRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Watchtowerrpc_GetInfoResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The public key of the watchtower.
var pubkey: Data = SwiftProtobuf.Internal.emptyData
/// The listening addresses of the watchtower.
var listeners: [String] = []
/// The URIs of the watchtower.
var uris: [String] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "watchtowerrpc"
extension Watchtowerrpc_GetInfoRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GetInfoRequest"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Watchtowerrpc_GetInfoRequest, rhs: Watchtowerrpc_GetInfoRequest) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Watchtowerrpc_GetInfoResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GetInfoResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pubkey"),
2: .same(proto: "listeners"),
3: .same(proto: "uris"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.pubkey)
case 2: try decoder.decodeRepeatedStringField(value: &self.listeners)
case 3: try decoder.decodeRepeatedStringField(value: &self.uris)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.pubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.pubkey, fieldNumber: 1)
}
if !self.listeners.isEmpty {
try visitor.visitRepeatedStringField(value: self.listeners, fieldNumber: 2)
}
if !self.uris.isEmpty {
try visitor.visitRepeatedStringField(value: self.uris, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Watchtowerrpc_GetInfoResponse, rhs: Watchtowerrpc_GetInfoResponse) -> Bool {
if lhs.pubkey != rhs.pubkey {return false}
if lhs.listeners != rhs.listeners {return false}
if lhs.uris != rhs.uris {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -0,0 +1,673 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: wtclientrpc/wtclient.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct Wtclientrpc_AddTowerRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The identifying public key of the watchtower to add.
var pubkey: Data = SwiftProtobuf.Internal.emptyData
/// A network address the watchtower is reachable over.
var address: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_AddTowerResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_RemoveTowerRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The identifying public key of the watchtower to remove.
var pubkey: Data = SwiftProtobuf.Internal.emptyData
///
///If set, then the record for this address will be removed, indicating that is
///is stale. Otherwise, the watchtower will no longer be used for future
///session negotiations and backups.
var address: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_RemoveTowerResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_GetTowerInfoRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The identifying public key of the watchtower to retrieve information for.
var pubkey: Data = SwiftProtobuf.Internal.emptyData
/// Whether we should include sessions with the watchtower in the response.
var includeSessions: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_TowerSession {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The total number of successful backups that have been made to the
///watchtower session.
var numBackups: UInt32 = 0
///
///The total number of backups in the session that are currently pending to be
///acknowledged by the watchtower.
var numPendingBackups: UInt32 = 0
/// The maximum number of backups allowed by the watchtower session.
var maxBackups: UInt32 = 0
///
///The fee rate, in satoshis per vbyte, that will be used by the watchtower for
///the justice transaction in the event of a channel breach.
var sweepSatPerByte: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_Tower {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The identifying public key of the watchtower.
var pubkey: Data = SwiftProtobuf.Internal.emptyData
/// The list of addresses the watchtower is reachable over.
var addresses: [String] = []
/// Whether the watchtower is currently a candidate for new sessions.
var activeSessionCandidate: Bool = false
/// The number of sessions that have been negotiated with the watchtower.
var numSessions: UInt32 = 0
/// The list of sessions that have been negotiated with the watchtower.
var sessions: [Wtclientrpc_TowerSession] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_ListTowersRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Whether we should include sessions with the watchtower in the response.
var includeSessions: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_ListTowersResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The list of watchtowers available for new backups.
var towers: [Wtclientrpc_Tower] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_StatsRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_StatsResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The total number of backups made to all active and exhausted watchtower
///sessions.
var numBackups: UInt32 = 0
///
///The total number of backups that are pending to be acknowledged by all
///active and exhausted watchtower sessions.
var numPendingBackups: UInt32 = 0
///
///The total number of backups that all active and exhausted watchtower
///sessions have failed to acknowledge.
var numFailedBackups: UInt32 = 0
/// The total number of new sessions made to watchtowers.
var numSessionsAcquired: UInt32 = 0
/// The total number of watchtower sessions that have been exhausted.
var numSessionsExhausted: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_PolicyRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct Wtclientrpc_PolicyResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
///The maximum number of updates each session we negotiate with watchtowers
///should allow.
var maxUpdates: UInt32 = 0
///
///The fee rate, in satoshis per vbyte, that will be used by watchtowers for
///justice transactions in response to channel breaches.
var sweepSatPerByte: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "wtclientrpc"
extension Wtclientrpc_AddTowerRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".AddTowerRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pubkey"),
2: .same(proto: "address"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.pubkey)
case 2: try decoder.decodeSingularStringField(value: &self.address)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.pubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.pubkey, fieldNumber: 1)
}
if !self.address.isEmpty {
try visitor.visitSingularStringField(value: self.address, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_AddTowerRequest, rhs: Wtclientrpc_AddTowerRequest) -> Bool {
if lhs.pubkey != rhs.pubkey {return false}
if lhs.address != rhs.address {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_AddTowerResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".AddTowerResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_AddTowerResponse, rhs: Wtclientrpc_AddTowerResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_RemoveTowerRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".RemoveTowerRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pubkey"),
2: .same(proto: "address"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.pubkey)
case 2: try decoder.decodeSingularStringField(value: &self.address)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.pubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.pubkey, fieldNumber: 1)
}
if !self.address.isEmpty {
try visitor.visitSingularStringField(value: self.address, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_RemoveTowerRequest, rhs: Wtclientrpc_RemoveTowerRequest) -> Bool {
if lhs.pubkey != rhs.pubkey {return false}
if lhs.address != rhs.address {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_RemoveTowerResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".RemoveTowerResponse"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_RemoveTowerResponse, rhs: Wtclientrpc_RemoveTowerResponse) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_GetTowerInfoRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GetTowerInfoRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pubkey"),
2: .standard(proto: "include_sessions"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.pubkey)
case 2: try decoder.decodeSingularBoolField(value: &self.includeSessions)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.pubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.pubkey, fieldNumber: 1)
}
if self.includeSessions != false {
try visitor.visitSingularBoolField(value: self.includeSessions, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_GetTowerInfoRequest, rhs: Wtclientrpc_GetTowerInfoRequest) -> Bool {
if lhs.pubkey != rhs.pubkey {return false}
if lhs.includeSessions != rhs.includeSessions {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_TowerSession: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TowerSession"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "num_backups"),
2: .standard(proto: "num_pending_backups"),
3: .standard(proto: "max_backups"),
4: .standard(proto: "sweep_sat_per_byte"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularUInt32Field(value: &self.numBackups)
case 2: try decoder.decodeSingularUInt32Field(value: &self.numPendingBackups)
case 3: try decoder.decodeSingularUInt32Field(value: &self.maxBackups)
case 4: try decoder.decodeSingularUInt32Field(value: &self.sweepSatPerByte)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.numBackups != 0 {
try visitor.visitSingularUInt32Field(value: self.numBackups, fieldNumber: 1)
}
if self.numPendingBackups != 0 {
try visitor.visitSingularUInt32Field(value: self.numPendingBackups, fieldNumber: 2)
}
if self.maxBackups != 0 {
try visitor.visitSingularUInt32Field(value: self.maxBackups, fieldNumber: 3)
}
if self.sweepSatPerByte != 0 {
try visitor.visitSingularUInt32Field(value: self.sweepSatPerByte, fieldNumber: 4)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_TowerSession, rhs: Wtclientrpc_TowerSession) -> Bool {
if lhs.numBackups != rhs.numBackups {return false}
if lhs.numPendingBackups != rhs.numPendingBackups {return false}
if lhs.maxBackups != rhs.maxBackups {return false}
if lhs.sweepSatPerByte != rhs.sweepSatPerByte {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_Tower: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Tower"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pubkey"),
2: .same(proto: "addresses"),
3: .standard(proto: "active_session_candidate"),
4: .standard(proto: "num_sessions"),
5: .same(proto: "sessions"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBytesField(value: &self.pubkey)
case 2: try decoder.decodeRepeatedStringField(value: &self.addresses)
case 3: try decoder.decodeSingularBoolField(value: &self.activeSessionCandidate)
case 4: try decoder.decodeSingularUInt32Field(value: &self.numSessions)
case 5: try decoder.decodeRepeatedMessageField(value: &self.sessions)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.pubkey.isEmpty {
try visitor.visitSingularBytesField(value: self.pubkey, fieldNumber: 1)
}
if !self.addresses.isEmpty {
try visitor.visitRepeatedStringField(value: self.addresses, fieldNumber: 2)
}
if self.activeSessionCandidate != false {
try visitor.visitSingularBoolField(value: self.activeSessionCandidate, fieldNumber: 3)
}
if self.numSessions != 0 {
try visitor.visitSingularUInt32Field(value: self.numSessions, fieldNumber: 4)
}
if !self.sessions.isEmpty {
try visitor.visitRepeatedMessageField(value: self.sessions, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_Tower, rhs: Wtclientrpc_Tower) -> Bool {
if lhs.pubkey != rhs.pubkey {return false}
if lhs.addresses != rhs.addresses {return false}
if lhs.activeSessionCandidate != rhs.activeSessionCandidate {return false}
if lhs.numSessions != rhs.numSessions {return false}
if lhs.sessions != rhs.sessions {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_ListTowersRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ListTowersRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "include_sessions"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularBoolField(value: &self.includeSessions)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.includeSessions != false {
try visitor.visitSingularBoolField(value: self.includeSessions, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_ListTowersRequest, rhs: Wtclientrpc_ListTowersRequest) -> Bool {
if lhs.includeSessions != rhs.includeSessions {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_ListTowersResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ListTowersResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "towers"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeRepeatedMessageField(value: &self.towers)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.towers.isEmpty {
try visitor.visitRepeatedMessageField(value: self.towers, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_ListTowersResponse, rhs: Wtclientrpc_ListTowersResponse) -> Bool {
if lhs.towers != rhs.towers {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_StatsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".StatsRequest"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_StatsRequest, rhs: Wtclientrpc_StatsRequest) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_StatsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".StatsResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "num_backups"),
2: .standard(proto: "num_pending_backups"),
3: .standard(proto: "num_failed_backups"),
4: .standard(proto: "num_sessions_acquired"),
5: .standard(proto: "num_sessions_exhausted"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularUInt32Field(value: &self.numBackups)
case 2: try decoder.decodeSingularUInt32Field(value: &self.numPendingBackups)
case 3: try decoder.decodeSingularUInt32Field(value: &self.numFailedBackups)
case 4: try decoder.decodeSingularUInt32Field(value: &self.numSessionsAcquired)
case 5: try decoder.decodeSingularUInt32Field(value: &self.numSessionsExhausted)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.numBackups != 0 {
try visitor.visitSingularUInt32Field(value: self.numBackups, fieldNumber: 1)
}
if self.numPendingBackups != 0 {
try visitor.visitSingularUInt32Field(value: self.numPendingBackups, fieldNumber: 2)
}
if self.numFailedBackups != 0 {
try visitor.visitSingularUInt32Field(value: self.numFailedBackups, fieldNumber: 3)
}
if self.numSessionsAcquired != 0 {
try visitor.visitSingularUInt32Field(value: self.numSessionsAcquired, fieldNumber: 4)
}
if self.numSessionsExhausted != 0 {
try visitor.visitSingularUInt32Field(value: self.numSessionsExhausted, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_StatsResponse, rhs: Wtclientrpc_StatsResponse) -> Bool {
if lhs.numBackups != rhs.numBackups {return false}
if lhs.numPendingBackups != rhs.numPendingBackups {return false}
if lhs.numFailedBackups != rhs.numFailedBackups {return false}
if lhs.numSessionsAcquired != rhs.numSessionsAcquired {return false}
if lhs.numSessionsExhausted != rhs.numSessionsExhausted {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_PolicyRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".PolicyRequest"
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let _ = try decoder.nextFieldNumber() {
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_PolicyRequest, rhs: Wtclientrpc_PolicyRequest) -> Bool {
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Wtclientrpc_PolicyResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".PolicyResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "max_updates"),
2: .standard(proto: "sweep_sat_per_byte"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularUInt32Field(value: &self.maxUpdates)
case 2: try decoder.decodeSingularUInt32Field(value: &self.sweepSatPerByte)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.maxUpdates != 0 {
try visitor.visitSingularUInt32Field(value: self.maxUpdates, fieldNumber: 1)
}
if self.sweepSatPerByte != 0 {
try visitor.visitSingularUInt32Field(value: self.sweepSatPerByte, fieldNumber: 2)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Wtclientrpc_PolicyResponse, rhs: Wtclientrpc_PolicyResponse) -> Bool {
if lhs.maxUpdates != rhs.maxUpdates {return false}
if lhs.sweepSatPerByte != rhs.sweepSatPerByte {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

33
wallet/Main.storyboard Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--HomeVC-->
<scene sceneID="s0d-6b-0kx">
<objects>
<viewController id="Y6W-OH-hqX" customClass="HomeVC" customModule="wallet" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
<color key="backgroundColor" systemColor="systemPinkColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="139" y="42"/>
</scene>
</scenes>
<resources>
<systemColor name="systemPinkColor">
<color red="1" green="0.17647058823529413" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

View File

@ -0,0 +1,20 @@
//
// ExampleRepository.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class ExampleRepository {
// Perform fake request
func getRandomInt(onSuccess: @escaping (Int) -> Void, onFailure: @escaping (Error) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
onSuccess(Int.random(in: 1..<100))
}
}
}

View File

@ -0,0 +1,310 @@
//
// LightningRepository.swift
// wallet
//
// Created by Jason on 8/30/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class LightningRepository {
func createWallet(password: String, onSuccess: @escaping ([String]) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.generateSeed { [weak self] (seed, error) in
guard let self = self else { return }
guard error == nil else {
onFailure(error)
return
}
Lightning.shared.createWallet(password: password, cipherSeedMnemonic: seed) { [weak self] (error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(seed)
}
}
}
func closeChannel(channel:Lnrpc_Channel, onSuccess: @escaping (Lnrpc_ClosedChannelsResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.closeChannel(channel: channel) { response, error in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 Close Channel error ", response)
onSuccess(response)
}
}
func openChannel(localFunding: Int64, pushSat: Int64, host: String, port: UInt, nodePubKey: NodePublicKey, closeAddress: String?, onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.connectToNode(nodePubkey: nodePubKey, hostAddress: host, hostPort: port) { [weak self] (response, error) in
if error != nil && error?.localizedDescription.contains("already connected to peer") == false {
debugPrint("🔆🔆🔆🔆🔆 Connect to node error ", error)
onFailure(error)
return
}
onSuccess("Connected to peer")
Lightning.shared.openChannel(localFundingAmount: localFunding, pushSat: pushSat, closeAddress: closeAddress, nodePubkey: nodePubKey) { (response, error) in
guard error == nil else {
debugPrint("❤️❤️❤️❤️❤️❤️❤️ Open Channel error ", error)
onFailure(error)
return
}
guard let update = response.update else {
return
}
switch update {
case .chanPending(let pendingUpdate):
onSuccess("Channel open pending update\nTXID: \(pendingUpdate.txid.base64EncodedString())")
case .chanOpen(let openUpdate):
onSuccess("Channel open success update")
case .psbtFund(let onpsbtFund):
onSuccess("I don't know why you would get this error")
}
}
}
}
func listChannels(onSuccess: @escaping (Lnrpc_ListChannelsResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.listChannels { (response, error) in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 List Channel error ", response)
onSuccess(response)
}
}
func listClosedChannels(onSuccess: @escaping (Lnrpc_ClosedChannelsResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.listClosedChannels { (response, error) in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 List Channel error ", response)
onSuccess(response)
}
}
func listPendingChannels(onSuccess: @escaping (Lnrpc_PendingChannelsResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.listPendingChannels { (response, error) in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 List Pending Channel error ", response)
onSuccess(response)
}
}
func getChannelInfo(id: UInt64, onSuccess: @escaping (Lnrpc_ChannelEdge) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.getChanInfo(id: id) { (response, error) in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 Get Channel info error ", response)
onSuccess(response)
}
}
func listPeers(onSuccess: @escaping (Lnrpc_ListPeersResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.listPeers { [weak self] (response, error) in
if error != nil && error?.localizedDescription.contains("already connected to peer") == false {
onFailure(error)
return
}
debugPrint("Listing peers ", response)
onSuccess(response)
}
}
func listInvoices(onSuccess: @escaping (Lnrpc_ListInvoiceResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.listInvoices { (response, error) in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 List Invoices error ", response)
for payment in response.invoices{
Lightning.shared.queryRequestFee(key: payment.fallbackAddr) { responseQuery, error in
debugPrint("Query request fee", responseQuery, error)
}
}
onSuccess(response)
}
}
func listPayments(onSuccess: @escaping (Lnrpc_ListPaymentsResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.listPayments { (response, error) in
guard error == nil else {
onFailure(error)
return
}
debugPrint("👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻 List Payments error ", response)
onSuccess(response)
}
}
func wipeWallet(onSuccess: @escaping () -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.stop { (error) in
guard error == nil else {
onFailure(error)
return
}
Lightning.shared.purge()
onSuccess()
}
}
func getWalletBalance(onSuccess: @escaping (_ total: Int64, _ confirmed: Int64, _ unconfirmed: Int64) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.walletBalance { [weak self] (balanceResponse, error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(
balanceResponse.totalBalance,
balanceResponse.confirmedBalance,
balanceResponse.unconfirmedBalance
)
}
}
func getNewAddress(onSuccess: @escaping (String) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.newAddress { [weak self] (address, error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(address)
}
}
func getInfo(onSuccess: @escaping (Lnrpc_GetInfoResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.info { [weak self] (info, error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(info)
}
}
func unlockWallet(password: String, onSuccess: @escaping () -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.unlockWalet(password: password) { [weak self] (error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess()
}
}
func createInvoice(amount: Int, memo: String, onSuccess: @escaping (Lnrpc_AddInvoiceResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.createPayRequest(amount: amount, memo: memo) { [weak self] (response, error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(response)
}
}
func getPaymentInfo(paymentRequest: String, onSuccess: @escaping (Lnrpc_PayReq) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.decodePaymentRequest(paymentRequest) { [weak self] (decodedResponse, error) in
debugPrint("Decoded response", decodedResponse)
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(decodedResponse)
}
}
func getLightningChannelBalance(onSuccess: @escaping (_ balance: Lnrpc_ChannelBalanceResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.lightningChannelBalance { [weak self] (balanceResponse, error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(balanceResponse)
}
}
func estimateFee(address: String, amount: Int64, onSuccess: @escaping (Lnrpc_EstimateFeeResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.estimateFee(address, amount: amount) { response, error in
guard error == nil else {
onFailure(error)
return
}
debugPrint("Estimate fee response",response)
onSuccess(response)
}
}
func feeReport(onSuccess: @escaping (Lnrpc_FeeReportResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.feeReport(){ response, error in
guard error == nil else {
onFailure(error)
return
}
debugPrint("Fee Report fee response",response)
onSuccess(response)
}
}
func pay(paymentRequest: String, onSuccess: @escaping (Lnrpc_SendResponse) -> Void, onFailure: @escaping (Error?) -> Void) {
Lightning.shared.decodePaymentRequest(paymentRequest) { [weak self] (decodedResponse, error) in
debugPrint("Decoded response", decodedResponse)
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
//Requst decoded succesfully so can be used to make the payment
Lightning.shared.payRequest(paymentRequest) { [weak self] (sendResponse, error) in
guard self != nil else { return }
guard error == nil else {
onFailure(error)
return
}
onSuccess(sendResponse)
}
}
}
}

View File

@ -0,0 +1,82 @@
//
// SceneDelegate.swift
// wallet
//
// Created by Jason on 8/12/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let navigationController = UINavigationController(rootViewController: HomeVC())
window.rootViewController = navigationController
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
guard !Settings.isUnitTest else {
return
}
Lightning.shared.start({ (error) in
guard error == nil else {
return print("LND start error")
}
}) { (error) in
guard error == nil else {
return print("RPC startup error")
}
}
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
Lightning.shared.stop { (error) in
guard error == nil else {
return print("LND stop error")
}
print("LND stopped")
}
}
}

19
wallet/Utils/Colors.swift Normal file
View File

@ -0,0 +1,19 @@
//
// Colors.swift
// wallet
//
// Created by Jason on 8/20/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
extension UIColor {
public static let yellow500 = #colorLiteral(red: 1, green: 0.9176470588, blue: 0, alpha: 1)
public static let yellow600 = #colorLiteral(red: 0.9294117647, green: 0.8549019608, blue: 0.03137254902, alpha: 1)
public static let purple500 = #colorLiteral(red: 0.6156862745, green: 0.2352941176, blue: 1, alpha: 1)
public static let gray900 = #colorLiteral(red: 0.07058823529, green: 0.07058823529, blue: 0.07058823529, alpha: 1)
public static let white500 = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
}

23
wallet/Utils/Dimens.swift Normal file
View File

@ -0,0 +1,23 @@
//
// Dimens.swift
// wallet
//
// Created by Jason on 8/27/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
struct Dimens {
public static let tall = 72
public static let button = 56
public static let bar = 88
public static let minButtonWidth = 140
public static let chip = 44
public static let titleText = 20
public static let normalText = 16
public static let mediumMargin = 16
public static let shadow = 2
}

View File

@ -0,0 +1,24 @@
//
// Date.swift
// wallet
//
// Created by Adriana Epure on 24.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import Foundation
extension Date{
func adding(minutes: Int) -> Date {
return Calendar.current.date(byAdding: .minute, value: minutes, to: self)!
}
func adding(seconds: Int) -> Date {
return Calendar.current.date(byAdding: .second, value: seconds, to: self)!
}
func format(style: DateFormatter.Style)->String{
let utcDateFormatter = DateFormatter()
utcDateFormatter.dateStyle = style
utcDateFormatter.timeStyle = style
return utcDateFormatter.string(from: self)
}
}

View File

@ -0,0 +1,15 @@
//
// Date.swift
// wallet
//
// Created by Adriana Epure on 24.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import Foundation
extension Int64{
func getAsDate()->Date{
return Date(timeIntervalSince1970: TimeInterval(self))
}
}

View File

@ -0,0 +1,38 @@
//
// Misc.swift
// wallet
//
// Created by Jason on 8/30/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
extension String {
func toQR(scale: CGFloat = 15.0) -> UIImage? {
let data = self.data(using: String.Encoding.ascii)
// Create the filter and transform it's scale
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: scale, y: scale)
if let output = filter.outputImage?.transformed(by: transform) {
return UIImage(ciImage: output)
}
}
return nil
}
}

View File

@ -0,0 +1,17 @@
//
// UIImageView.swift
// wallet
//
// Created by Jason on 8/27/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
extension UIImage {
func tint(_ color: UIColor) -> UIImage {
return withRenderingMode(.alwaysTemplate).withTintColor(color)
}
}

View File

@ -0,0 +1,22 @@
//
// UIView.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
extension UIView {
func addSubviewAndFill(_ view: UIView, top: CGFloat = 0.0, bottom: CGFloat = 0.0, leading: CGFloat = 0.0, trailing: CGFloat = 0.0) {
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.topAnchor.constraint(equalTo: topAnchor, constant: top).isActive = true
view.leadingAnchor.constraint(equalTo: leadingAnchor, constant: leading).isActive = true
view.trailingAnchor.constraint(equalTo: trailingAnchor, constant: trailing).isActive = true
view.bottomAnchor.constraint(equalTo: bottomAnchor, constant: bottom).isActive = true
}
}

View File

@ -0,0 +1,58 @@
//
// UIViewController.swift
// wallet
//
// Created by Jason van den Berg on 2020/08/18.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
extension UIViewController {
func setTheme() {
view.backgroundColor = Theme.backgroundColor
setNavBarStyles()
}
func setNavBarStyles() {
// Color
navigationController?.navigationBar.barTintColor = Theme.backgroundColor
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = Theme.inverseBackgroundColor
// Shadow
navigationController?.navigationBar.layer.shadowColor = Theme.shadowColor.cgColor
navigationController?.navigationBar.layer.shadowOffset = CGSize(width: 0.0, height: CGFloat(Dimens.shadow))
navigationController?.navigationBar.layer.shadowRadius = 0.0
navigationController?.navigationBar.layer.shadowOpacity = 1.0
navigationController?.navigationBar.layer.masksToBounds = false
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .any, barMetrics: .default)
navigationController?.navigationBar.shadowImage = UIImage()
// Text
navigationController?.navigationBar.titleTextAttributes = [
NSAttributedString.Key.foregroundColor: Theme.inverseBackgroundColor,
NSAttributedString.Key.font: Fonts.sofiaPro(weight: .medium, Dimens.titleText)
]
}
func hideKeyboardWhenSwipedDown() {
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
swipeDown.direction = UISwipeGestureRecognizer.Direction.down
view.addGestureRecognizer(swipeDown)
}
func hideKeyboardWhenTappedAround() {
let tap = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc func dismissKeyboard() {
view.endEditing(true)
}
}

31
wallet/Utils/Fonts.swift Normal file
View File

@ -0,0 +1,31 @@
//
// Fonts.swift
// wallet
//
// Created by Jason on 8/20/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
public enum FontStyle {
case regular
case medium
case bold
var name: String {
switch self {
case .regular: return "SofiaProRegular"
case .medium: return "SofiaProMedium"
case .bold: return "SofiaProBold"
}
}
}
struct Fonts {
public static func sofiaPro(weight: FontStyle = .regular, _ size: Int = 16) -> UIFont {
return UIFont(name: weight.name, size: CGFloat(size))!
}
}

16
wallet/Utils/Icons.swift Normal file
View File

@ -0,0 +1,16 @@
//
// Icons.swift
// wallet
//
// Created by Jason on 8/27/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
extension UIImage {
public static let back = #imageLiteral(resourceName: "ic_back")
public static let delete = #imageLiteral(resourceName: "ic_backspace")
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,30 @@
//
// Observable.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class Observable<T> {
private let thread: DispatchQueue
var value: T? {
willSet(newValue) {
if let newValue = newValue {
thread.async {
self.observe?(newValue)
}
}
}
}
var observe: ((T) -> ())?
init(_ value: T? = nil, thread dispatcherThread: DispatchQueue = DispatchQueue.main) {
self.thread = dispatcherThread
self.value = value
}
}

View File

@ -0,0 +1,13 @@
//
// Settings.swift
// wallet
//
// Created by Jason van den Berg on 2020/08/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class Settings {
static var isUnitTest = ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
}

View File

@ -0,0 +1,21 @@
//
// Strings.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
extension String {
public static let defaultError = NSLocalizedString("DEFAULT_ERROR", comment: "A fallback error")
public static let request = NSLocalizedString("REQUEST", comment: "Request")
public static let note = NSLocalizedString("NOTE", comment: "Note")
public static let next = NSLocalizedString("NEXT", comment: "Next")
public static let createQR = NSLocalizedString("CREATE_QR", comment: "Create a QR code")
public static let forLabel = NSLocalizedString("FOR", comment: "For")
public static let requestNotePlaceholder = NSLocalizedString("NOTE_PLACEHOLDER", comment: "Placeholder for the note")
}

63
wallet/Utils/Theme.swift Normal file
View File

@ -0,0 +1,63 @@
//
// Theme.swift
// wallet
//
// Created by Jason on 8/20/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
struct Theme {
public static let primaryColor: UIColor = {
return UIColor { (UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .systemTeal
} else {
return .systemTeal
}
}
}()
public static let primaryDarkColor: UIColor = {
return UIColor { (UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .systemBlue
} else {
return .systemBlue
}
}
}()
public static let backgroundColor: UIColor = {
return UIColor { (UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .gray900
} else {
return .white500
}
}
}()
public static let inverseBackgroundColor: UIColor = {
return UIColor { (UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .white500
} else {
return .gray900
}
}
}()
public static let shadowColor: UIColor = {
return UIColor { (UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return UIColor.white500.withAlphaComponent(0.25)
} else {
return UIColor.gray900.withAlphaComponent(0.25)
}
}
}()
}

View File

@ -0,0 +1,431 @@
//
// ChannelsVC.swift
// wallet
//
// Created by Adriana Epure on 22.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import UIKit
class ChannelsVC: CustomViewController<ChannelsViewModel> {
private let nodeKeyPlaceholder: String = "Public Node Key ..."
@IBOutlet weak var selectedListControl: UISegmentedControl!
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var channelsBtnsStack: UIStackView!
@IBOutlet weak var availableBalanceLbl: UILabel!
//MARK: Open Channel Outlets
@IBOutlet weak var newStackView: UIStackView!
@IBOutlet weak var newBtn: UIButton!
@IBOutlet weak var openAddressTextView: UITextView!
@IBOutlet weak var openBtn: UIButton!
@IBOutlet weak var cancelOpen: UIButton!
@IBOutlet weak var localFundingStepper: UIStepper!
@IBOutlet weak var pushAmountStepper: UIStepper!
@IBOutlet weak var localFundingAmount: UITextField!
@IBOutlet weak var closeAddressTextField: UITextField!
@IBOutlet weak var hostAddress: UITextField!
@IBOutlet weak var portTextField: UITextField!
@IBOutlet weak var pushSatAmount: UITextField!
lazy var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action:
#selector(refreshData(_:)),
for: .valueChanged)
refreshControl.tintColor = UIColor.gray
return refreshControl
}()
override func viewDidLoad() {
super.viewDidLoad()
title = "Channels"
self.selectedListControl.selectedSegmentIndex = 0
self.selectedListControl.sendActions(for: .valueChanged)
tableView.delegate = self
tableView.dataSource = self
}
override func viewModelDidLoad() {
viewModel.channels.observe = { [weak self] channels in
self?.tableView.reloadData()
}
viewModel.pendingChannels.observe = { [weak self] channels in
self?.tableView.reloadData()
}
viewModel.closedChannels.observe = { [weak self] channels in
self?.tableView.reloadData()
}
viewModel.peers.observe = { [weak self] peers in
self?.tableView.reloadData()
}
viewModel.walletBalance.observe = { [weak self] walletBalance in
self?.availableBalanceLbl.text = String(walletBalance.total)
}
viewModel.load()
viewModel.getWalletBalance()
self.tableView.addSubview(self.refreshControl)
}
@objc private func refreshData(_ sender: Any) {
// Fetch Weather Data
refreshList()
self.tableView.reloadData()
refreshControl.endRefreshing()
}
//MARK: - New Channel
@IBAction func didPressNewBtn(_ sender: UIButton) {
openAddressTextView.text = nodeKeyPlaceholder
openAddressTextView.textColor = UIColor.lightGray
openAddressTextView.delegate = self
openAddressTextView.layer.borderColor = UIColor.lightGray.cgColor
openAddressTextView.layer.borderWidth = 1
closeAddressTextField.delegate = self
localFundingAmount.delegate = self
pushSatAmount.delegate = self
showHideViews(isNew: true, isFinished: false)
openAddressTextView.text = "0245fc5e867abb5b83ead35b50dc5013dd358b9f3eb48c02f5e1cc9fc675039359"
}
@IBAction func didChangePushSatStepper(_ sender: UIStepper) {
pushSatAmount.text = String(String(format: "%.f", sender.value))
toggleOpenBtn()
}
@IBAction func didChangeLocalFundingStepper(_ sender: UIStepper) {
localFundingAmount.text = String(String(format: "%.f", sender.value))
toggleOpenBtn()
}
@IBAction func didPressOpenBtn(_ sender: UIButton) {
self.selectedListControl.selectedSegmentIndex = 0
self.selectedListControl.sendActions(for: .valueChanged)
if let channelAddress = openAddressTextView.text{
guard let pubKey = openAddressTextView.text else {
return
}
guard let host = hostAddress.text else {
return
}
guard let port = UInt(portTextField.text ?? "") else {
return
}
guard let funding = Int(localFundingAmount.text ?? "") else {
return
}
guard let push = Int(pushSatAmount.text ?? "") else {
return
}
debugPrint("Channel Address ", channelAddress)
viewModel.openChannel(nodePubKey: pubKey, hostAddress: host, port: port, pushSat: push, localFunding: funding) { response in
self.showAlert(title: "Channel Open", errorMsg: "Channel Open Request Sent")
} onFailure: { error in
self.showAlert(title: "Channel Open", errorMsg: "Channel Open Request Failed")
}
}
showHideViews(isNew: true, isFinished: true)
}
@IBAction func didPressCancelOpenBtn(_ sender: UIButton) {
showHideViews(isNew: !newStackView.isHidden, isFinished: true)
}
//MARK: - Selection
@IBAction func didChangeSelection(_ sender: Any) {
refreshList()
tableView.reloadData()
}
}
extension ChannelsVC{
func refreshList(){
switch selectedListControl.selectedSegmentIndex{
case 0:
viewModel.listChannels()
case 1:
viewModel.listClosedChannels()
case 2, 3:
viewModel.listPendingChannels()
default:
viewModel.listPeers()
}
}
func toggleOpenBtn(){
openBtn.isHidden = true
let isNodeKeyFilled = !openAddressTextView.text.isEmpty && openAddressTextView.textColor != UIColor.lightGray
let isCloseAddressFilled = !(closeAddressTextField.text?.isEmpty ?? true)
guard let localFundingText = localFundingAmount.text else {
return
}
guard let pushSatText = pushSatAmount.text else {
return
}
openBtn.isHidden = !(isNodeKeyFilled && Int(localFundingText) ?? 0 > 0 && Int(pushSatText) ?? 0 > 0)
}
func showHideViews(isNew: Bool, isFinished: Bool){
channelsBtnsStack.isHidden = !isFinished
newStackView.isHidden = isFinished || (!isFinished && !isNew)
tableView.isHidden = !isFinished
selectedListControl.isHidden = !isFinished
// openBtn.isHidden = true
if isFinished{
localFundingAmount.text = ""
localFundingAmount.text = "0"
openAddressTextView.text = ""
}
}
}
//MARK: - List
extension ChannelsVC: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
if selectedListControl.selectedSegmentIndex == 0 {
return viewModel.channels.value?[indexPath.row].active ?? false
} else {
return false
}
}
func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
return "Close"
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if selectedListControl.selectedSegmentIndex == 0 && editingStyle == .delete{
if let channel = viewModel.channels.value?[indexPath.row]{
debugPrint(channel)
let showAlert = UIAlertController(title: "Close Channel", message: "Are you sure you want to close this channel?", preferredStyle: .alert)
showAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
self.viewModel.closeChannel(channel: channel) { response in
self.showAlert(title: "Closed Channel", description: "Channel Close Request Sent")
} onFailure: { error in
self.showAlert(title: "Closed Channel", description: "Channel Close Request Failed")
}
debugPrint("✅✅ Close channel ✅✅")
}))
showAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
self.viewModel.listChannels()
}))
self.present(showAlert, animated: true, completion: nil)
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
emptyLabel.text = ""
emptyLabel.textAlignment = NSTextAlignment.center
self.tableView.backgroundView = emptyLabel
switch selectedListControl.selectedSegmentIndex{
case 0:
if let noOfChannels = viewModel.channels.value?.count{
return noOfChannels
}else{
emptyLabel.text = "No channels"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
case 1:
if let noOfClosedChannels = viewModel.closedChannels.value?.count{
return noOfClosedChannels
}else{
emptyLabel.text = "No closed channels"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
case 2:
if let noOfPendingChannels = viewModel.pendingChannels.value?.pendingOpenChannels.count {
return noOfPendingChannels
}else{
emptyLabel.text = "No pending open channels"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
case 3:
if let noOfPendingChannels = viewModel.pendingChannels.value?.waitingCloseChannels.count {
return noOfPendingChannels
}else{
emptyLabel.text = "No pending closed channels"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
default:
if let noOfPeers = viewModel.peers.value?.count{
return noOfPeers
}else{
emptyLabel.text = "No Peers"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let reuseCellIdentifier = "cellIdentifier"
var cell = tableView.dequeueReusableCell(withIdentifier: reuseCellIdentifier)
if (!(cell != nil)) {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: reuseCellIdentifier)
}
cell?.textLabel?.numberOfLines = 0
cell?.detailTextLabel?.numberOfLines = 0
switch selectedListControl.selectedSegmentIndex{
case 0:
if let channel = viewModel.channels.value?[indexPath.row]{
cell?.textLabel?.text = "Status: \(channel.active ? "active" : "inactive") \nFee per Kw: \(channel.feePerKw) sat \nUptime: \(channel.uptime) "
cell?.detailTextLabel?.text = "\nLocal Balance: \(channel.localBalance) sat \nRemote Balance: \(channel.remoteBalance) sat \nUnsettled balance: \(channel.unsettledBalance) sat \nPublic key: \(channel.remotePubkey)"
}
case 1:
if let channel = viewModel.closedChannels.value?[indexPath.row]{
cell?.textLabel?.text = "\nSettled Balance per Kw: \(channel.settledBalance) sat \nCapacity: \(channel.capacity) "
cell?.detailTextLabel?.text = "\nOpen by: \(channel.openInitiator) sat \nClosed by: \(channel.closeInitiator) sat \nTime Locked balance: \(channel.timeLockedBalance) sat \nPublic key: \(channel.remotePubkey)"
}
case 2:
if let channel = viewModel.pendingChannels.value?.pendingOpenChannels[indexPath.row] as? Lnrpc_PendingChannelsResponse.PendingOpenChannel{
debugPrint("Channel pending list", channel, indexPath)
cell?.textLabel?.text = "\n Pending Open "
cell?.detailTextLabel?.text = "\n \nCapacity: \(channel.channel.capacity) \nConfirmation Height \(channel.confirmationHeight) \nLocal Balance: \(channel.channel.localBalance) sat \nRemote Balance: \(channel.channel.remoteBalance) sat \n \(channel.channel.channelPoint)"
}
case 3:
if let channel = viewModel.pendingChannels.value?.waitingCloseChannels[indexPath.row] as? Lnrpc_PendingChannelsResponse.WaitingCloseChannel{
debugPrint("Channel pending list", channel, indexPath)
cell?.textLabel?.text = "\n Pending Close "
cell?.detailTextLabel?.text = "\n \nCapacity: \(channel.channel.capacity) \nLimbo Balance \(channel.limboBalance) \n\nLocal TX ID\(channel.commitments.localTxid) \n\nRemote TX ID\(channel.commitments.remoteTxid) \n\nLocal Commit Fee\(channel.commitments.localCommitFeeSat) sat \nRemote Commit Fee\(channel.commitments.remoteCommitFeeSat) sat \n\nLocal Balance: \(channel.channel.localBalance) sat \nRemote Balance: \(channel.channel.remoteBalance) sat \n \(channel.channel.channelPoint)"
}
default:
if let peer = viewModel.peers.value?[indexPath.row]{
cell?.textLabel?.text = "Received : \(peer.satRecv) sat \nSent: \(peer.satSent) sat "
cell?.detailTextLabel?.text = "\n Host: \(peer.address) \nInbound: \(peer.inbound) \nPing time:\(peer.pingTime) \nPublic key: \(peer.pubKey)"
}
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedListControl.selectedSegmentIndex == 0{
if let channel = viewModel.channels.value?[indexPath.row]{
self.viewModel.getChannelInfo(id: channel.chanID) { channelInfo in
debugPrint(channelInfo)
let info = "🕓 Last Update: \(Int64(channelInfo.lastUpdate).getAsDate().format(style: .medium)) \n💰Capacity: \(channelInfo.capacity)sat \n💰 RemoteBalance: \(channel.remoteBalance)sat \n💰Local Balance: \(channel.localBalance)sat \nPoint: \(channelInfo.chanPoint) \n\n✅->>>>>> Node 1 <<<<<<-✅\n\n💰 Base Fee:\(channelInfo.node1Policy.feeBaseMsat)sat\nFee Rate:\(channelInfo.node2Policy.feeRateMilliMsat)msat \nPublic key: \n\(channelInfo.node1Pub) \n\n✅->>>>>> Node 2 <<<<<<-✅\n\n💰 Base Fee:\(channelInfo.node2Policy.feeBaseMsat)sat\nFee Rate:\(channelInfo.node2Policy.feeRateMilliMsat)msat\nPublic key: \n\(channelInfo.node2Pub) "
self.showAlert(title: "Channel Info", description: info)
} onFailure: { error in
debugPrint(error)
}
}
}else{
if let peer = viewModel.peers.value?[indexPath.row]{
self.showAlert(title: "Peer", address: peer.pubKey)
}
}
}
}
extension ChannelsVC: UITextFieldDelegate{
/**
* Called when 'return' key pressed. return NO to ignore.
*/
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
toggleOpenBtn()
textField.resignFirstResponder()
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == localFundingAmount || textField == pushSatAmount{
let allowedCharacters = CharacterSet.decimalDigits
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
}
return true
}
/**
* Called when the user click on the view (outside the UITextField).
*/
func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
}
extension ChannelsVC: UITextPasteDelegate {
func textPasteConfigurationSupporting(_ textPasteConfigurationSupporting: UITextPasteConfigurationSupporting, shouldAnimatePasteOf attributedString: NSAttributedString, to textRange: UITextRange) -> Bool {
return false
}
}
extension ChannelsVC: UITextViewDelegate{
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == UIColor.lightGray {
textView.text = nil
textView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = nodeKeyPlaceholder
textView.textColor = UIColor.lightGray
}
}
func textViewDidChange(_ textView: UITextView) {
if(textView.text == UIPasteboard.general.string){
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Combine the textView text and the replacement text to
// create the updated text string
let currentText:String = textView.text
let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)
// If updated text view will be empty, add the placeholder
// and set the cursor to the beginning of the text view
if updatedText.isEmpty {
textView.text = nodeKeyPlaceholder
textView.textColor = UIColor.lightGray
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
// Else if the text view's placeholder is showing and the
// length of the replacement string is greater than 0, set
// the text color to black then set its text to the
// replacement string
else if textView.textColor == UIColor.lightGray && !text.isEmpty {
textView.textColor = UIColor.black
textView.text = text
}else if text == "\n" {
textView.resignFirstResponder()
toggleOpenBtn()
return false
}
// For every other case, the text should change with the usual
// behavior...
else {
return true
}
// ...otherwise return false since the updates have already
// been made
return false
}
func textViewDidChangeSelection(_ textView: UITextView) {
if self.view.window != nil {
if textView.textColor == UIColor.lightGray {
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
}
}
}

View File

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ChannelsVC" customModule="wallet" customModuleProvider="target">
<connections>
<outlet property="availableBalanceLbl" destination="0rv-hh-yTU" id="YJV-cH-7mD"/>
<outlet property="cancelOpen" destination="1z2-qr-1G2" id="fkX-KG-rol"/>
<outlet property="channelsBtnsStack" destination="h4H-Ut-Ezh" id="D3n-YI-Q04"/>
<outlet property="closeAddressTextField" destination="YYe-rx-c3w" id="JJe-UR-7zE"/>
<outlet property="hostAddress" destination="e2a-MX-Po7" id="Aoh-kM-wEu"/>
<outlet property="localFundingAmount" destination="La5-7h-5LH" id="p0M-ND-iyF"/>
<outlet property="localFundingStepper" destination="Uyt-iD-uLf" id="a0t-cG-U6p"/>
<outlet property="newBtn" destination="u7v-GW-Zcu" id="F1t-0F-Ezn"/>
<outlet property="newStackView" destination="EMx-u0-dZ0" id="gya-ja-rxd"/>
<outlet property="openAddressTextView" destination="HVV-61-fc4" id="ocL-Pq-gXa"/>
<outlet property="openBtn" destination="KXZ-8G-xlK" id="feZ-7c-cVF"/>
<outlet property="portTextField" destination="8Du-rx-ZO7" id="iy7-Iz-xhD"/>
<outlet property="pushAmountStepper" destination="8jb-gN-cXi" id="36O-o0-Gnw"/>
<outlet property="pushSatAmount" destination="Sl9-tu-l5C" id="Lvn-8N-l46"/>
<outlet property="selectedListControl" destination="quV-XT-L9U" id="MNo-Ve-4jN"/>
<outlet property="tableView" destination="CNO-2M-Ehd" id="mpP-7J-tTr"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="EbI-sn-GFX" userLabel="ChannelStack">
<rect key="frame" x="10" y="54" width="394" height="798"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="27A-G6-BKJ">
<rect key="frame" x="0.0" y="0.0" width="394" height="24"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Available Balance:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qld-17-jca">
<rect key="frame" x="0.0" y="0.0" width="321.5" height="24"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0rv-hh-yTU">
<rect key="frame" x="331.5" y="0.0" width="12.5" height="24"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Poe-ge-Ilm">
<rect key="frame" x="354" y="0.0" width="40" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="Ei2-DA-alP"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="h4H-Ut-Ezh" userLabel="Channel Buttons">
<rect key="frame" x="0.0" y="39" width="394" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="u7v-GW-Zcu">
<rect key="frame" x="0.0" y="0.0" width="394" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="d5o-dh-wsM"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="New" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressNewBtn:" destination="-1" eventType="touchUpInside" id="GYC-4M-B4L"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="DtU-1U-uV3">
<rect key="frame" x="0.0" y="94" width="394" height="339.5"/>
<subviews>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="EMx-u0-dZ0" userLabel="new">
<rect key="frame" x="0.0" y="0.0" width="571" height="310"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalCentering" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="02R-N8-t4A">
<rect key="frame" x="0.0" y="0.0" width="571" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Funding" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0IX-IG-L1X" userLabel="Funding">
<rect key="frame" x="0.0" y="5" width="61.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="20000" borderStyle="roundedRect" placeholder="Amount" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="La5-7h-5LH">
<rect key="frame" x="130.5" y="0.0" width="150" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="Ecx-Yc-mLv"/>
<constraint firstAttribute="width" constant="150" id="nxL-LP-usf"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" wraps="YES" value="100" maximumValue="9.2233720368547758e+18" stepValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="Uyt-iD-uLf">
<rect key="frame" x="333.5" y="0.0" width="94" height="30"/>
<connections>
<action selector="didChangeLocalFundingStepper:" destination="-1" eventType="valueChanged" id="DDl-LL-wRZ"/>
</connections>
</stepper>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bAR-HI-pY9">
<rect key="frame" x="539.5" y="5" width="31.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalCentering" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="221-mN-hvL">
<rect key="frame" x="0.0" y="40" width="571" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Push Sat" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CRA-2B-8MY" userLabel="Funding">
<rect key="frame" x="0.0" y="5" width="67.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="100" borderStyle="roundedRect" placeholder="Amount" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Sl9-tu-l5C">
<rect key="frame" x="132.5" y="0.0" width="150" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="Pgn-Fw-60H"/>
<constraint firstAttribute="height" constant="30" id="mN4-at-DVI"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" wraps="YES" value="100" maximumValue="9.2233720368547758e+18" stepValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="8jb-gN-cXi">
<rect key="frame" x="334.5" y="0.0" width="94" height="30"/>
<connections>
<action selector="didChangePushSatStepper:" destination="-1" eventType="valueChanged" id="u9z-Wi-lz2"/>
</connections>
</stepper>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iaC-rR-77q">
<rect key="frame" x="539.5" y="5" width="31.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<textView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" keyboardDismissMode="interactive" text="0245fc5e867abb5b83ead35b50dc5013dd358b9f3eb48c02f5e1cc9fc675039359" textAlignment="natural" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HVV-61-fc4">
<rect key="frame" x="0.0" y="80" width="571" height="150"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="150" id="KSm-OU-Bqo"/>
</constraints>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="12"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" enablesReturnKeyAutomatically="YES" smartDashesType="no" smartQuotesType="no"/>
</textView>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="02d38c9cdbc94a25438c473f96ba97450ca3897cdd86f4d2e64b04d97830316100" borderStyle="roundedRect" placeholder="Close Address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YYe-rx-c3w">
<rect key="frame" x="0.0" y="240" width="571" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
</textField>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="7qb-QX-2IG">
<rect key="frame" x="0.0" y="250" width="571" height="0.0"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="bmadesign.go.ro" borderStyle="roundedRect" placeholder="Host Address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="e2a-MX-Po7">
<rect key="frame" x="0.0" y="0.0" width="491" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="9735" borderStyle="roundedRect" placeholder="Port" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8Du-rx-ZO7">
<rect key="frame" x="501" y="0.0" width="70" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="70" id="vBn-Jn-9fI"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Srx-Kb-1BK">
<rect key="frame" x="0.0" y="260" width="571" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KXZ-8G-xlK">
<rect key="frame" x="0.0" y="0.0" width="571" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="5t6-4c-88b"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Open" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressOpenBtn:" destination="-1" eventType="touchUpInside" id="220-cB-njR"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1z2-qr-1G2">
<rect key="frame" x="0.0" y="50" width="571" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Cancel" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressCancelOpenBtn:" destination="-1" eventType="touchUpInside" id="caA-Xs-gyk"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sDf-4k-ftA" userLabel="List">
<rect key="frame" x="0.0" y="448.5" width="394" height="349.5"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Gil-tx-Uvy" userLabel="List Stack">
<rect key="frame" x="0.0" y="0.0" width="394" height="349.5"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="quV-XT-L9U">
<rect key="frame" x="0.0" y="0.0" width="394" height="41"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Mo3-l7-4DT"/>
</constraints>
<segments>
<segment title="Active"/>
<segment title="Closed"/>
<segment title="Opening"/>
<segment title="Closing"/>
<segment title="Peers"/>
</segments>
<connections>
<action selector="didChangeSelection:" destination="-1" eventType="valueChanged" id="yLp-lM-nT1"/>
</connections>
</segmentedControl>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" estimatedSectionHeaderHeight="-1" sectionFooterHeight="18" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="CNO-2M-Ehd">
<rect key="frame" x="0.0" y="50" width="394" height="299.5"/>
</tableView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="Gil-tx-Uvy" secondAttribute="bottom" id="3oK-i7-Ini"/>
<constraint firstItem="Gil-tx-Uvy" firstAttribute="leading" secondItem="sDf-4k-ftA" secondAttribute="leading" id="aNV-5U-3Jw"/>
<constraint firstAttribute="trailing" secondItem="Gil-tx-Uvy" secondAttribute="trailing" id="cEr-YJ-KsC"/>
<constraint firstItem="Gil-tx-Uvy" firstAttribute="top" secondItem="sDf-4k-ftA" secondAttribute="top" id="yoS-st-AZ9"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="EbI-sn-GFX" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="10" id="7c8-Qu-hWm"/>
<constraint firstItem="EbI-sn-GFX" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="10" id="I1r-ag-t3I"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="EbI-sn-GFX" secondAttribute="bottom" constant="10" id="OUL-fR-h4f"/>
<constraint firstAttribute="trailing" secondItem="EbI-sn-GFX" secondAttribute="trailing" constant="10" id="wsh-qt-mNT"/>
</constraints>
<point key="canvasLocation" x="139" y="96"/>
</view>
</objects>
<resources>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View File

@ -0,0 +1,125 @@
import UIKit
class CustomViewController<VM: ViewModel>: UIViewController {
private lazy var leftNavigationAction: () -> Void = {
self.navigationController?.popViewController(animated: true)
}
var viewModel: VM! {
didSet {
viewModelDidLoad()
}
}
lazy var loadingView: LoadingView = {
return LoadingView()
}()
lazy var errorView: ErrorView = {
return ErrorView()
}()
override func viewDidLoad() {
super.viewDidLoad()
// Create the view model if needed
if (viewModel == nil) {
viewModel = VM()
}
// setTheme()
}
public func showContentView() {
dropViews([errorView, loadingView])
}
public func showLoadingView() {
dropViews([errorView])
addViewIfNeeded(loadingView)
}
public func showErrorView(error: String = .defaultError) {
dropViews([loadingView])
addViewIfNeeded(errorView)
errorView.title = error
}
private func dropViews(_ views: [UIView]) {
views.forEach { view in
view.removeFromSuperview()
}
}
private func addViewIfNeeded(_ subview: UIView) {
if (!view.subviews.contains(subview)) {
view.addSubviewAndFill(subview)
view.bringSubviewToFront(subview)
}
}
func viewModelDidLoad() {
// Empty
}
@objc private func leftAction() {
leftNavigationAction()
}
func setLeftNavigationButton(_ icon: UIImage, action: (() -> Void)? = nil) {
// Attach left action
// Or fallback with a pop
if let leftAction = action {
leftNavigationAction = leftAction
} else {
leftNavigationAction = {
self.navigationController?.popViewController(animated: true)
}
}
navigationItem.leftBarButtonItem = UIBarButtonItem(
image: .back,
style: .plain,
target: self,
action: #selector(CustomViewController.leftAction)
)
}
func showAlert(title: String, address: String? = nil , errorMsg: String? = nil, description: String? = nil){
let showAlert = UIAlertController(title: title, message: errorMsg, preferredStyle: .alert)
if let address = address {
let imageView = UIImageView(frame: CGRect(x: 10, y: 50, width: 250, height: 250))
imageView.image = generateQRCode(from: address)
imageView.layer.magnificationFilter = CALayerContentsFilter.nearest
showAlert.view.addSubview(imageView)
let height = NSLayoutConstraint(item: showAlert.view as Any, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 400)
let width = NSLayoutConstraint(item: showAlert.view as Any, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant:250)
showAlert.view.addConstraint(height)
showAlert.view.addConstraint(width)
showAlert.addAction(UIAlertAction(title: "Copy Address", style: .default, handler: { action in
UIPasteboard.general.string = address
debugPrint("✅✅ Created Invoice ✅✅", address)
}))
}
if let description = description {
showAlert.message = description
}
showAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
}))
self.present(showAlert, animated: true, completion: nil)
}
func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let QRFilter = CIFilter(name: "CIQRCodeGenerator") {
QRFilter.setValue(data, forKey: "inputMessage")
guard let QRImage = QRFilter.outputImage else {return nil}
return UIImage(ciImage: QRImage)
}
return nil
}
}

View File

@ -0,0 +1,16 @@
//
// Home.swift
// wallet
//
// Created by Adriana Epure on 19.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import UIKit
class Home: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
}
}

View File

@ -0,0 +1,166 @@
//
// HomeVC.swift
// wallet
//
// Created by Adriana Epure on 19.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import UIKit
class HomeVC: CustomViewController<HomeViewModel> {
private let password = "sshhhhhh"
/// LND Status
@IBOutlet weak var debugStatus: UILabel!
@IBOutlet weak var lndStatus: UIImageView!
@IBOutlet weak var syncToChainStatus: UIImageView!
@IBOutlet weak var walletStatus: UIImageView!
/// INFO
@IBOutlet weak var infoStack: UIStackView!
@IBOutlet weak var peersCount: UILabel!
@IBOutlet weak var blockHeightCount: UILabel!
@IBOutlet weak var activeChannelsCount: UILabel!
@IBOutlet weak var inactiveChannelsCount: UILabel!
@IBOutlet weak var pendingChannelsCount: UILabel!
/// Wallet
@IBOutlet weak var walletStack: UIStackView!
@IBOutlet weak var walletBalanceStack: UIStackView!
@IBOutlet weak var createWalletBtn: UIButton!
@IBOutlet weak var unlockWalletBtn: UIButton!
@IBOutlet weak var getBalanceBtn: UIButton!
@IBOutlet weak var walletInfo: UIButton!
@IBOutlet weak var totalAmountLbl: UILabel!
@IBOutlet weak var unconfirmedLbl: UILabel!
@IBOutlet weak var confirmedAmountLbl: UILabel!
@IBOutlet weak var showChannelsBtn: UIButton!
@IBOutlet weak var showPaymentsBtn: UIButton!
//MARK: View LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
title = "Home"
updateStatus()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
subscribe()
}
//MARK: ViewModel
// This will get called when the ViewModel for this ViewController is ready to use
// This gives us a simple place to observe all changes to the datasources
// and can update the views accordingly as they change in real time
override func viewModelDidLoad() {
viewModel.isLoading.observe = { [weak self] isLoading in
if (isLoading) {
self?.showLoadingView()
}else{
self?.showContentView()
}
}
viewModel.walletBalance.observe = { [weak self] balance in
self?.updateBalance(balance)
}
viewModel.newAddress.observe = { [weak self] address in
UIPasteboard.general.string = address
self?.showContentView()
}
viewModel.walletWipe.observe = { _ in
UIControl().sendAction(#selector(NSXPCConnection.suspend), to: UIApplication.shared, for: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
exit(0)
}
}
viewModel.load()
}
//MARK: Button Actions
@IBAction func didPressUnlockBtn(_ sender: Any) {
self.viewModel.unlockWallet(password: self.password)
}
@IBAction func didPressPaymentsBtn(_ sender: Any) {
self.navigationController?.pushViewController(PaymentsVC(), animated: true)
}
@IBAction func didPressChannelsBtn(_ sender: Any) {
self.navigationController?.pushViewController(ChannelsVC(), animated: true)
}
@IBAction func didPressWalletInfo(_ sender: Any) {
let walletAddress = LightningStateMonitor.shared.state.walletInfo.identityPubkey
self.showAlert(title: "My Wallet", address: walletAddress)
}
}
//MARK: Subscribe
extension HomeVC{
private func subscribe() {
EventBus.onMainThread(self, eventType: .lndStateChange) { [weak self] (_) in
self?.updateStatus()
}
EventBus.onMainThread(self, eventType: .lndStopped) { [weak self] (_) in
self?.updateStatus()
}
EventBus.onMainThread(self, eventType: .lndStarted) { [weak self] (_) in
self?.updateStatus()
}
EventBus.onMainThread(self, eventType: .lndRpcReady) { [weak self] (_) in
self?.updateStatus()
}
EventBus.onMainThread(self, eventType: .lndWalletUnlocked) { [weak self] (_) in
self?.updateStatus()
}
}
private func updateStatus() {
debugStatus.text = LightningStateMonitor.shared.state.debuggingStatus.joined(separator: "\n\n")
updateLND(isOn: LightningStateMonitor.shared.state.lndRunning)
updateRPC(isReady: LightningStateMonitor.shared.state.walletInfo.syncedToChain)
updateWallet(isUnlocked: LightningStateMonitor.shared.state.walletUnlocked)
updateInfo()
}
private func updateRPC(isReady: Bool){
self.syncToChainStatus.tintColor = isReady ? .green : .red
self.syncToChainStatus.image = isReady ? UIImage(systemName: "point.3.filled.connected.trianglepath.dotted") : UIImage(systemName: "point.3.connected.trianglepath.dotted")
}
private func updateLND(isOn: Bool){
self.unlockWalletBtn.isHidden = !isOn
self.unlockWalletBtn.isEnabled = isOn
self.lndStatus.tintColor = isOn ? .green : .red
self.lndStatus.image = isOn ? UIImage(systemName: "checkmark.circle.fill") : UIImage(systemName: "checkmark.circle.trianglebadge.exclamationmark")
}
private func updateInfo(){
self.peersCount.text = String(LightningStateMonitor.shared.state.walletInfo.numPeers)
self.blockHeightCount.text = String(LightningStateMonitor.shared.state.walletInfo.blockHeight)
self.activeChannelsCount.text = String(LightningStateMonitor.shared.state.walletInfo.numActiveChannels)
self.inactiveChannelsCount.text = String(LightningStateMonitor.shared.state.walletInfo.numInactiveChannels)
self.pendingChannelsCount.text = String(LightningStateMonitor.shared.state.walletInfo.numPendingChannels)
self.viewModel.getWalletBalance()
}
private func updateBalance(_ balance: WalletBalance){
self.totalAmountLbl.text = String(balance.total)
self.confirmedAmountLbl.text = String(balance.confirmed)
self.unconfirmedLbl.text = String(balance.unconfirmed)
}
private func updateWallet(isUnlocked: Bool){
self.unlockWalletBtn.isHidden = isUnlocked
self.walletStatus.tintColor = isUnlocked ? .green : .red
self.walletStatus.image = isUnlocked ? UIImage(systemName: "lock.open") : UIImage(systemName: "lock")
self.infoStack.isHidden = !isUnlocked
self.walletBalanceStack.isHidden = !isUnlocked
self.walletInfo.isEnabled = isUnlocked
// self.getBalanceBtn.isHidden = !isUnlocked
self.showChannelsBtn.isHidden = !isUnlocked
self.showPaymentsBtn.isEnabled = isUnlocked
}
}

View File

@ -0,0 +1,440 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_5" orientation="portrait" appearance="dark"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="HomeVC" customModule="wallet" customModuleProvider="target">
<connections>
<outlet property="activeChannelsCount" destination="zRx-dK-uJE" id="hJw-ZA-d9E"/>
<outlet property="blockHeightCount" destination="5QF-aB-AzD" id="n2p-N1-Tel"/>
<outlet property="confirmedAmountLbl" destination="34J-jN-Q91" id="zpC-6E-Ok0"/>
<outlet property="createWalletBtn" destination="xQO-ma-Ns5" id="K4y-qs-XZ6"/>
<outlet property="debugStatus" destination="mtl-Cw-2ae" id="h4l-VD-qjQ"/>
<outlet property="getBalanceBtn" destination="CMf-Ai-3KB" id="16m-QG-cYf"/>
<outlet property="inactiveChannelsCount" destination="z52-zh-U2d" id="aut-SY-5pH"/>
<outlet property="infoStack" destination="QHZ-Pz-mB5" id="m3u-Ut-eoD"/>
<outlet property="lndStatus" destination="moD-HD-xh0" id="U8Q-r1-S47"/>
<outlet property="peersCount" destination="76Q-p1-XZ1" id="rFt-mP-giC"/>
<outlet property="pendingChannelsCount" destination="r5R-Ev-Seq" id="aw7-R3-fcR"/>
<outlet property="showChannelsBtn" destination="cRk-fH-Sad" id="prH-j5-kr0"/>
<outlet property="showPaymentsBtn" destination="HsC-Xa-Y3H" id="1DT-TI-4Us"/>
<outlet property="syncToChainStatus" destination="3tZ-K3-N1j" id="Wmd-iV-8JM"/>
<outlet property="totalAmountLbl" destination="4pG-Su-HTw" id="2E6-Fd-v27"/>
<outlet property="unconfirmedLbl" destination="oG3-SU-sEx" id="JfP-wy-geo"/>
<outlet property="unlockWalletBtn" destination="8rQ-o3-AmK" id="LpW-s0-hhl"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
<outlet property="walletBalanceStack" destination="g7X-9x-bt4" id="fZ5-98-bOU"/>
<outlet property="walletInfo" destination="UUx-4i-0lO" id="UC6-rd-IRY"/>
<outlet property="walletStack" destination="dOk-rZ-J6T" id="LFC-QZ-tB4"/>
<outlet property="walletStatus" destination="Mga-vz-Vve" id="u4y-bw-Hlj"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="0pU-hv-ExQ">
<rect key="frame" x="10" y="54" width="394" height="788"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="zrD-Fl-hXg" userLabel="StatusStack">
<rect key="frame" x="0.0" y="0.0" width="394" height="60"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="Pwi-0u-4yk">
<rect key="frame" x="0.0" y="15" width="234" height="30"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="moD-HD-xh0">
<rect key="frame" x="0.0" y="2.6666666666666661" width="76.666666666666671" height="24.666666666666671"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" systemColor="systemGrayColor"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="NsX-6W-jbc"/>
</constraints>
<imageReference key="image" image="checkmark.circle.trianglebadge.exclamationmark" catalog="system" symbolScale="small"/>
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small" weight="thin"/>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="3tZ-K3-N1j">
<rect key="frame" x="79.666666666666657" y="3.6666666666666661" width="74.666666666666657" height="22.666666666666671"/>
<color key="tintColor" systemColor="systemGrayColor"/>
<imageReference key="image" image="point.3.connected.trianglepath.dotted" catalog="system" symbolScale="small"/>
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small" weight="thin"/>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mga-vz-Vve">
<rect key="frame" x="159.33333333333334" y="3" width="74.666666666666657" height="24.333333333333332"/>
<color key="tintColor" systemColor="systemGrayColor"/>
<imageReference key="image" image="lock" catalog="system" symbolScale="small"/>
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small" weight="thin"/>
</imageView>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UUx-4i-0lO" userLabel="Info">
<rect key="frame" x="239" y="0.0" width="60" height="60"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="88V-J5-ieg"/>
<constraint firstAttribute="height" constant="60" id="vZp-sM-V5f"/>
</constraints>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<buttonConfiguration key="configuration" style="filled" cornerStyle="capsule">
<imageReference key="image" image="qrcode" catalog="system" symbolScale="medium"/>
<preferredSymbolConfiguration key="preferredSymbolConfigurationForImage" configurationType="pointSize" pointSize="20" scale="large" weight="semibold"/>
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" systemColor="linkColor"/>
</buttonConfiguration>
<connections>
<action selector="didPressWalletInfo:" destination="-1" eventType="touchUpInside" id="JNL-dT-UCs"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HsC-Xa-Y3H">
<rect key="frame" x="304" y="5" width="90" height="50"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="90" id="9yo-Yc-O4q"/>
<constraint firstAttribute="height" constant="50" id="iEh-z3-hvt"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" subtitle="Pay" cornerStyle="capsule">
<imageReference key="image" image="bitcoinsign.circle" catalog="system" symbolScale="large"/>
<preferredSymbolConfiguration key="preferredSymbolConfigurationForImage" configurationType="pointSize" pointSize="20" scale="large" weight="semibold"/>
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" systemColor="systemOrangeColor"/>
</buttonConfiguration>
<connections>
<action selector="didPressPaymentsBtn:" destination="-1" eventType="touchUpInside" id="LPn-Qm-1PI"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="749" axis="vertical" distribution="fillEqually" alignment="bottom" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="g7X-9x-bt4" userLabel="Wallet Balance">
<rect key="frame" x="0.0" y="109.66666666666666" width="394" height="140"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="YbH-8J-Eic" userLabel="confirmed">
<rect key="frame" x="242.33333333333337" y="0.0" width="151.66666666666663" height="40"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Confirmed:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lT4-v6-dVB">
<rect key="frame" x="0.0" y="0.0" width="79" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="APC-iW-MxF"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="34J-jN-Q91">
<rect key="frame" x="88.999999999999972" y="0.0" width="12.666666666666671" height="40"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2Z6-YT-Kob">
<rect key="frame" x="111.66666666666666" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="7Nn-QB-LRG"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Kll-eU-fOU" userLabel="unconfirmed">
<rect key="frame" x="224.66666666666663" y="50" width="169.33333333333337" height="40"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Unconfirmed:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4SM-6U-tSR">
<rect key="frame" x="0.0" y="0.0" width="96.666666666666671" height="40"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oG3-SU-sEx">
<rect key="frame" x="106.66666666666666" y="0.0" width="12.666666666666671" height="40"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="njc-NA-8nJ">
<rect key="frame" x="129.33333333333334" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="j6y-xc-Byo"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="8bk-xS-8Ds" userLabel="total">
<rect key="frame" x="276.66666666666669" y="100.00000000000003" width="117.33333333333331" height="40"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Total:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bxa-dN-D7e">
<rect key="frame" x="0.0" y="0.0" width="43" height="40"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="18"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<size key="shadowOffset" width="0.0" height="0.0"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4pG-Su-HTw">
<rect key="frame" x="53" y="0.0" width="14.333333333333329" height="40"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<size key="shadowOffset" width="0.0" height="0.0"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dGo-sv-6hu">
<rect key="frame" x="77.333333333333314" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="RXw-3N-Uj7"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="16"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<size key="shadowOffset" width="0.0" height="0.0"/>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mtl-Cw-2ae">
<rect key="frame" x="0.0" y="252" width="394" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="dOk-rZ-J6T" userLabel="WalletStack">
<rect key="frame" x="0.0" y="299" width="394" height="40"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="H2Y-SL-XLi" userLabel="Wallet Buttons">
<rect key="frame" x="0.0" y="0.0" width="394" height="40"/>
<subviews>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xQO-ma-Ns5">
<rect key="frame" x="0.0" y="0.0" width="0.0" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="muc-i9-WwF"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Create" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
</button>
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8rQ-o3-AmK">
<rect key="frame" x="0.0" y="0.0" width="394" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Unlock Wallet" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressUnlockBtn:" destination="-1" eventType="touchUpInside" id="4b5-gu-sMm"/>
</connections>
</button>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CMf-Ai-3KB">
<rect key="frame" x="0.0" y="0.0" width="0.0" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Balance" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<view contentMode="scaleToFill" horizontalHuggingPriority="248" verticalHuggingPriority="248" horizontalCompressionResistancePriority="748" verticalCompressionResistancePriority="748" translatesAutoresizingMaskIntoConstraints="NO" id="gD8-f1-4TU">
<rect key="frame" x="0.0" y="388.66666666666669" width="394" height="200.00000000000006"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="200" id="628-eh-ADF"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="top" translatesAutoresizingMaskIntoConstraints="NO" id="QHZ-Pz-mB5" userLabel="InfoStack">
<rect key="frame" x="0.0" y="638" width="394" height="150"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="top" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="xVn-YK-0hG" userLabel="Channels">
<rect key="frame" x="0.0" y="0.0" width="394" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Channels" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C0U-J3-vOX">
<rect key="frame" x="0.0" y="0.0" width="67.666666666666671" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="fG4-Fs-83T">
<rect key="frame" x="97.666666666666657" y="0.0" width="296.33333333333337" height="50"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="5GJ-Z1-dgb" userLabel="Active">
<rect key="frame" x="0.0" y="0.0" width="66.666666666666671" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Active" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ayo-OT-ABI">
<rect key="frame" x="0.0" y="0.0" width="66.666666666666671" height="20"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zRx-dK-uJE">
<rect key="frame" x="0.0" y="30" width="66.666666666666671" height="20"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="cGI-uh-7h5" userLabel="Inactive">
<rect key="frame" x="76.666666666666657" y="0.0" width="66.666666666666657" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Inactive" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rFx-Ct-9Zm">
<rect key="frame" x="0.0" y="0.0" width="66.666666666666671" height="20"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="z52-zh-U2d">
<rect key="frame" x="0.0" y="30" width="66.666666666666671" height="20"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="hjZ-X3-0Kf" userLabel="Pending">
<rect key="frame" x="153.33333333333331" y="0.0" width="66.333333333333314" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Pending" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JFg-pm-GM8">
<rect key="frame" x="0.0" y="0.0" width="66.333333333333329" height="20"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="r5R-Ev-Seq">
<rect key="frame" x="0.0" y="30" width="66.333333333333329" height="20"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hxv-8W-wtx">
<rect key="frame" x="229.6666666666666" y="0.0" width="66.666666666666657" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="infoLight" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cRk-fH-Sad">
<rect key="frame" x="18" y="9.6666666666666305" width="30.666666666666671" height="30.666666666666671"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<buttonConfiguration key="configuration" style="filled" cornerStyle="capsule">
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressChannelsBtn:" destination="-1" eventType="touchUpInside" id="2by-Nc-Q38"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="cRk-fH-Sad" firstAttribute="centerY" secondItem="hxv-8W-wtx" secondAttribute="centerY" id="91x-dp-SXn"/>
<constraint firstItem="cRk-fH-Sad" firstAttribute="centerX" secondItem="hxv-8W-wtx" secondAttribute="centerX" id="HFS-Wc-T0S"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="hxi-E5-mQF" userLabel="Peers">
<rect key="frame" x="0.0" y="50" width="98" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Peers:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dwh-ZT-Vmb">
<rect key="frame" x="0.0" y="0.0" width="44" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="yvc-Yu-47d"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="76Q-p1-XZ1">
<rect key="frame" x="54" y="0.0" width="44" height="50"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="cZP-5r-IM1" userLabel="Block Height">
<rect key="frame" x="0.0" y="100" width="196.66666666666666" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Block Height:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UMC-sR-S7c">
<rect key="frame" x="0.0" y="0.0" width="93.333333333333329" height="50"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5QF-aB-AzD">
<rect key="frame" x="103.33333333333334" y="0.0" width="93.333333333333343" height="50"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" systemColor="systemIndigoColor"/>
<constraints>
<constraint firstItem="0pU-hv-ExQ" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="10" id="01s-KR-a0w"/>
<constraint firstItem="0pU-hv-ExQ" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="10" id="eN5-Op-IFT"/>
<constraint firstAttribute="trailing" secondItem="0pU-hv-ExQ" secondAttribute="trailing" constant="10" id="egw-G9-8mQ"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="0pU-hv-ExQ" secondAttribute="bottom" constant="20" id="qAQ-eR-X6h"/>
</constraints>
<point key="canvasLocation" x="137.68115942028987" y="71.651785714285708"/>
</view>
</objects>
<resources>
<image name="bitcoinsign.circle" catalog="system" width="128" height="121"/>
<image name="checkmark.circle.trianglebadge.exclamationmark" catalog="system" width="128" height="108"/>
<image name="lock" catalog="system" width="128" height="128"/>
<image name="point.3.connected.trianglepath.dotted" catalog="system" width="128" height="96"/>
<image name="qrcode" catalog="system" width="128" height="114"/>
<systemColor name="linkColor">
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemGrayColor">
<color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemIndigoColor">
<color red="0.34509803921568627" green="0.33725490196078434" blue="0.83921568627450982" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemOrangeColor">
<color red="1" green="0.58431372549019611" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

View File

@ -0,0 +1,519 @@
import UIKit
class HomeViewController: CustomViewController<HomeViewModel> {
// private let password = "sshhhhhh"
// private var unlockWallet : UIButton!
// private var getInfo : UIButton!
// private var listChannels : UIButton!
// private var openChannel : UIButton!
// private var showInvoices : UIButton!
// private var showPayments : UIButton!
// private var hideButton : UIButton!
// private var sendPayment : UIButton!
// private var receivePayment : UIButton!
// private var cancel : UIButton!
// private var generateInvoice : UIButton!
// private var payInvoice : UIButton!
// private var debugStatus : UILabel!
// private var resultMessage : UILabel!
// private var balance : UILabel!
// private var invoiceLbl : UILabel!
// var isShowPayments: Bool = true
// lazy var contentViewSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
// lazy var scrollView: UIScrollView = {
// let view = UIScrollView(frame: .zero)
// view.backgroundColor = .white
// view.frame = self.view.bounds
// view.contentSize = contentViewSize
// view.translatesAutoresizingMaskIntoConstraints = false
// return view
// }()
// lazy var stackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .vertical
// stackView.distribution = .fill
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// lazy var debugStackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .vertical
// stackView.distribution = .fill
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// lazy var walletStackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .vertical
// stackView.distribution = .fill
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// lazy var infoStackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .vertical
// stackView.distribution = .fill
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// lazy var channelStackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .vertical
// stackView.distribution = .fill
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// lazy var paymentStackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .vertical
// stackView.distribution = .fill
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// lazy var sendStackView: UIStackView = {
// let stackView = UIStackView()
// stackView.axis = .horizontal
// stackView.distribution = .fillEqually
// stackView.alignment = .fill
// stackView.spacing = 10
// stackView.translatesAutoresizingMaskIntoConstraints = false
// return stackView
// }()
// let textView: UITextField = {
// let textView = UITextField()
// textView.textAlignment = .left
// textView.layer.cornerRadius = 5.0
// textView.layer.borderWidth = 0.2
// textView.layer.borderColor = UIColor.gray.cgColor
// textView.layer.masksToBounds = true
// textView.tintColor = .black
// textView.translatesAutoresizingMaskIntoConstraints = false //enable autolayout
// textView.heightAnchor.constraint(equalToConstant: 100).isActive = true
// textView.isHidden = true
// textView.placeholder = "Enter Invoice..."
//// textView.text = "lntb2500n1p30mapmpp53jy8q39upxn0acs5a2e0hzducxn25f2r9xrp3y7kyje2ug68t4lqdqgf4jhycmfcqzpgxqrrsssp5qe7unjq3j2lw7f8etvlhsgpac8ec7q7pd3ydx6mmaa33vcjcl5as9qyyssq2w3e8d074cz72tmmne9z7c3j9f9u8n3elc2sgzdm7j760847c5az2ca6900tdg7hx8wnaethzqkq60ym4ug7zrr4mlxyzcc5lrvgwycqmyzteq"
// return textView
// }()
// lazy var tableView: UITableView = {
// let tableView: UITableView = UITableView()
// tableView.backgroundColor = .white
// tableView.translatesAutoresizingMaskIntoConstraints = false
// tableView.heightAnchor.constraint(equalToConstant: 200).isActive = true
// tableView.delegate = self
// tableView.dataSource = self
// return tableView
// }()
//
//
// override func viewDidLoad() {
// super.viewDidLoad()
// title = "LND test"
// view.backgroundColor = .white
// view.addSubview(scrollView)
// scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
// scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
// scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
// scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
// setup()
// scrollView.addSubview(stackView)
//
// stackView.translatesAutoresizingMaskIntoConstraints = false
// stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -40).isActive = true
// stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10).isActive = true
// stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 20).isActive = true
// stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: 20).isActive = true
// stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 10).isActive = true
// updateStatus()
// }
//
// override func viewDidAppear(_ animated: Bool) {
// super.viewDidAppear(animated)
// subscribe()
// }
//
// private func subscribe() {
// EventBus.onMainThread(self, eventType: .lndStateChange) { [weak self] (_) in
// self?.updateStatus()
// }
// EventBus.onMainThread(self, eventType: .lndWalletUnlocked) { [weak self] (_) in
// self?.setupInfo()
// self?.setupChannel()
// self?.walletStackView.isHidden = true
// self?.viewModel.getWalletBalance()
// }
// }
//
// private func updateStatus() {
// if LightningStateMonitor.shared.state.lndRunning {
// setupWallet()
// }
//
// debugStatus.text = LightningStateMonitor.shared.state.debuggingStatus.joined(separator: "\n")
// }
//
// private func createButton(_ title: String, action: @escaping () -> Void) -> UIButton {
// let button = CustomButton(action: action)
// button.title = title
// button.translatesAutoresizingMaskIntoConstraints = false
// button.heightAnchor.constraint(equalToConstant: CGFloat(50)).isActive = true
// return button
// }
//
// private func setup() {
// let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
// view.addGestureRecognizer(tap) // Add gesture recognizer to background view
// showLNDStatus()
//
// textView.delegate = self
//
// }
//
// // This will get called when the ViewModel for this ViewController is ready to use
// // This gives us a simple place to observe all changes to the datasources
// // and can update the views accordingly as they change in real time
// override func viewModelDidLoad() {
//
// viewModel.isLoading.observe = { [weak self] isLoading in
// if (isLoading) {
// self?.showLoadingView()
// }
// }
//
// viewModel.randomInt.observe = { [weak self] randomInt in
// self?.showContentView()
// }
//
// viewModel.error.observe = { [weak self] error in
// self?.showErrorView()
// }
//
// viewModel.resultMessage.observe = { [weak self] message in
// self?.resultMessage.text = message
// self?.showContentView()
// }
//
// viewModel.newAddress.observe = { [weak self] address in
// self?.resultMessage.text = address
// UIPasteboard.general.string = address
// self?.showContentView()
// }
//
// viewModel.walletWipe.observe = { _ in
// UIControl().sendAction(#selector(NSXPCConnection.suspend), to: UIApplication.shared, for: nil)
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// exit(0)
// }
// }
// viewModel.payments.observe = { [weak self] payments in
// self?.tableView.reloadData()
// }
// viewModel.channels.observe = { [weak self] payments in
// self?.tableView.reloadData()
// }
// viewModel.balance.observe = { [weak self] balance in
// self?.balance.text = balance
// }
// viewModel.invoice.observe = { [weak self] invoice in
// self?.invoiceLbl.text = invoice
// }
// viewModel.load()
//
// }
//
//}
//extension HomeViewController: UITextFieldDelegate{
// @objc func handleTap() {
// textView.resignFirstResponder() // dismiss keyoard
// }
//
// func textFieldDidBeginEditing(_ textField: UITextField) {
// scrollView.setContentOffset(CGPoint(x: 0, y: textField.frame.height), animated: true)
// }
// func textFieldDidEndEditing(_ textField: UITextField) {
//
// if textField.hasText{
// payInvoice.isHidden = false
// }
// scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
// }
// func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// textField.resignFirstResponder() // dismiss keyboard
// return true
// }
//}
//extension HomeViewController: UITextPasteDelegate {
// func textPasteConfigurationSupporting(_ textPasteConfigurationSupporting: UITextPasteConfigurationSupporting, shouldAnimatePasteOf attributedString: NSAttributedString, to textRange: UITextRange) -> Bool {
// return false
// }
//}
////MARK: - Wallet Management
//extension HomeViewController{
// private func setupWallet(){
//
// // let createButton = addDebugButton("Create wallet", action: {
// // self.viewModel.createWallet(password: self.password)
// // })
// // let newAddressButton = addDebugButton("New address (copies to clipboard)", action: {
// // self.viewModel.getNewAddress()
// // })
// // let wipeButton = addDebugButton("Wipe (and close) wallet", action: {
// // self.viewModel.wipeWallet()
// // })
// unlockWallet = createButton("Unlock wallet", action: {
// self.viewModel.unlockWallet(password: self.password)
// self.balance = UILabel()
// self.balance.text = "..."
// self.balance.textColor = .blue
// self.balance.translatesAutoresizingMaskIntoConstraints = false
// self.balance.textAlignment = .center
// self.balance.numberOfLines = 0
// self.stackView.addArrangedSubview(self.balance)
// })
// walletStackView.addArrangedSubview(unlockWallet)
//
// stackView.addArrangedSubview(walletStackView)
//
// }
//}
////MARK: - Info
//extension HomeViewController{
// private func showLNDStatus(){
//
// resultMessage = UILabel()
// resultMessage.text = "..."
// resultMessage.translatesAutoresizingMaskIntoConstraints = false
// resultMessage.textColor = Theme.inverseBackgroundColor
// resultMessage.textAlignment = .center
// resultMessage.numberOfLines = 0
//
// debugStatus = UILabel()
// debugStatus.translatesAutoresizingMaskIntoConstraints = false
// debugStatus.textColor = Theme.inverseBackgroundColor
// debugStatus.textAlignment = .center
// debugStatus.numberOfLines = 0
// debugStatus.text = "Debug status"
// debugStackView.addArrangedSubview(resultMessage)
// debugStackView.addArrangedSubview(debugStatus)
// stackView.addArrangedSubview(debugStackView)
// }
// private func setupInfo(){
// getInfo = createButton("Show info", action: {
// self.viewModel.getInfo()
// self.viewModel.getWalletBalance()
// })
// infoStackView.addArrangedSubview(getInfo)
// stackView.addArrangedSubview(infoStackView)
//
// }
//}
//
////MARK: - Channel
//extension HomeViewController{
//
// private func setupChannel(){
// openChannel = createButton("Open channel", action: {
// self.viewModel.openChannel()
// })
// listChannels = createButton("List channels", action: {
// self.isShowPayments = false
// self.showHideViews(showChannels: false, showPayments: true)
// self.viewModel.listChannels()
//
// })
// channelStackView.addArrangedSubview(openChannel)
// channelStackView.addArrangedSubview(listChannels)
// stackView.addArrangedSubview(channelStackView)
//
//
// if viewModel.infoResponse.value?.numActiveChannels == 0 {
// listChannels.isHidden = false
// }else{
// openChannel.isHidden = true
// }
// setupPayments()
// }
//
//}
//
////MARK: - Payments Management
//extension HomeViewController: UITableViewDelegate, UITableViewDataSource{
// func showHideViews(showChannels: Bool, showPayments: Bool){
// let isListShowing = (showChannels == showPayments) && showChannels
// let isOneMissing = (showChannels && !showPayments) || (!showChannels && showPayments)
// self.showPayments.isHidden = !showPayments
// self.listChannels.isHidden = !showChannels
// self.hideButton.isHidden = !isOneMissing
// self.tableView.isHidden = !isOneMissing
// self.debugStackView.isHidden = !isListShowing
// self.infoStackView.isHidden = !isListShowing
// self.sendStackView.isHidden = !isListShowing
// }
// func showHideViews(showPay: Bool, showReceive: Bool){
// let hideOthers = !(showPay || showReceive)
// self.showHideViews(showChannels: hideOthers, showPayments: hideOthers)
// self.sendPayment.isHidden = showPay || showReceive
// self.receivePayment.isHidden = showPay || showReceive
// self.cancel.isHidden = showPay && showReceive
// self.payInvoice.isHidden = true
// self.generateInvoice.isHidden = true
// self.invoiceLbl.isHidden = true
// self.textView.isHidden = !showPay
// self.sendStackView.isHidden = false
//
// }
// private func setupPayments(){
//
// showInvoices = createButton("Show invoices", action: {
// self.viewModel.listInvoices()
// })
// hideButton = createButton("Hide", action: {
// self.showHideViews(showChannels: true, showPayments: true)
// })
// showPayments = createButton("Show Payments History", action: {
// self.isShowPayments = true
// self.showHideViews(showChannels: true, showPayments: false)
// self.viewModel.listPayments()
// })
//
//
// sendPayment = createButton("Send", action: {
// self.showHideViews(showPay: true, showReceive: false)
// })
// receivePayment = createButton("Receive", action: {
// self.showHideViews(showPay: false, showReceive: true)
// self.generateInvoice.isHidden = false
// self.invoiceLbl.isHidden = false
// })
// cancel = createButton("Cancel", action: {
// self.showHideViews(showChannels: true, showPayments: true)
// self.showHideViews(showPay: false, showReceive: false)
// self.cancel.isHidden = true
// })
// generateInvoice = createButton("Generate Invoice", action: {
// self.showHideViews(showChannels: true, showPayments: true)
// self.showHideViews(showPay: false, showReceive: false)
// self.viewModel.createInvoice(amount: 200, comment: self.textView.text ?? "Test")
// self.viewModel.getWalletBalance()
// })
// invoiceLbl = UILabel()
// invoiceLbl.text = "..."
// invoiceLbl.translatesAutoresizingMaskIntoConstraints = false
// invoiceLbl.numberOfLines = 0
//
// payInvoice = createButton("Pay Invoice", action: {
// if let text = self.textView.text{
// debugPrint("Invoice ", text)
// self.viewModel.payInvoice(invoice: text)
//
// }else{
//
// }
//
// self.viewModel.getWalletBalance()
// self.showHideViews(showChannels: true, showPayments: true)
// self.showHideViews(showPay: false, showReceive: false)
//
// })
//
// payInvoice.isHidden = true
// generateInvoice.isHidden = true
// invoiceLbl.isHidden = true
// tableView.isHidden = true
// hideButton.isHidden = true
// cancel.isHidden = true
// paymentStackView.addArrangedSubview(showInvoices)
// paymentStackView.addArrangedSubview(showPayments)
// paymentStackView.addArrangedSubview(hideButton)
//
//
// sendStackView.addArrangedSubview(sendPayment)
// sendStackView.addArrangedSubview(receivePayment)
// sendStackView.addArrangedSubview(cancel)
// sendStackView.addArrangedSubview(generateInvoice)
// sendStackView.addArrangedSubview(payInvoice)
//
// paymentStackView.addArrangedSubview(sendStackView)
// paymentStackView.addArrangedSubview(textView)
// paymentStackView.addArrangedSubview(invoiceLbl)
//
// paymentStackView.addArrangedSubview(tableView)
// stackView.addArrangedSubview(paymentStackView)
// }
//
// func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// if isShowPayments{
// if let noOfPayments = viewModel.payments.value?.count{
// return noOfPayments
// }else{
// let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
// emptyLabel.text = "No Payments"
// emptyLabel.textAlignment = NSTextAlignment.center
// self.tableView.backgroundView = emptyLabel
// self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
// return 0
// }
// }else{
// if let noOfChannels = viewModel.channels.value?.count{
// return noOfChannels
// }else{
// let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
// emptyLabel.text = "No Channels"
// emptyLabel.textAlignment = NSTextAlignment.center
// self.tableView.backgroundView = emptyLabel
// self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
// return 0
// }
// }
//
//
//
// }
//
// func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let reuseCellIdentifier = "cellIdentifier"
// var cell = tableView.dequeueReusableCell(withIdentifier: reuseCellIdentifier)
// if (!(cell != nil)) {
//
// cell = UITableViewCell(style: .subtitle, reuseIdentifier: reuseCellIdentifier)
// }
// cell?.textLabel?.numberOfLines = 0
// cell?.detailTextLabel?.numberOfLines = 0
// if isShowPayments{
// if let payment = viewModel.payments.value?[indexPath.row]{
// cell?.textLabel?.text = "Status: \(payment.status) \nAmount: \(payment.value) sat"
// cell?.detailTextLabel?.text = "\nDate: \(Date(timeIntervalSince1970: TimeInterval(payment.creationDate))) \nPayment hash:\n\(payment.paymentRequest.description)"
// }
// }else{
// if let channel = viewModel.channels.value?[indexPath.row]{
// cell?.textLabel?.text = "Active: \(channel.active) \nLocal Balance: \(channel.localBalance) sat \nRemote Balance: \(channel.remoteBalance) sat"
// let pendingTransactions = channel.pendingHtlcs.count == 0 ? "" : "\nPending transactions: \(channel.pendingHtlcs)"
// cell?.detailTextLabel?.text = "\nPub key: \(channel.remotePubkey) \(pendingTransactions)"
// }
// }
//
//
// return cell!
// }
}
public extension String {
func setColor(_ color: UIColor, ofSubstring substring: String) -> NSMutableAttributedString {
let range = (self as NSString).range(of: substring)
let attributedString = NSMutableAttributedString(string: self)
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
return attributedString
}
}

View File

@ -0,0 +1,403 @@
//
// PaymentsVC.swift
// wallet
//
// Created by Adriana Epure on 22.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import UIKit
import QRCodeScanner
class PaymentsVC: CustomViewController<PaymentsViewModel> {
@IBOutlet weak var paymentElements: UIStackView!
@IBOutlet weak var selectedListControl: UISegmentedControl!
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var paymentButtonsStack: UIStackView!
@IBOutlet weak var localBalanceValue: UILabel!
@IBOutlet weak var remoteBalanceValue: UILabel!
@IBOutlet weak var walletBalanceValue: UILabel!
@IBOutlet weak var estimateFeeValue: UILabel!
@IBOutlet weak var feeStackView: UIStackView!
//Send
@IBOutlet weak var sendStackView: UIStackView!
@IBOutlet weak var sendPaymentAddress: UITextView!
@IBOutlet weak var payBtn: UIButton!
@IBOutlet weak var paymentInfoStack: UIStackView!
@IBOutlet weak var paymentInfoLbl: UILabel!
@IBOutlet weak var memoLbl: UILabel!
@IBOutlet weak var paymentInfoCreated: UILabel!
@IBOutlet weak var paymentInfoExpiry: UILabel!
@IBOutlet weak var cancelPayBtn: UIButton!
//Receive
@IBOutlet weak var receiveStackView: UIStackView!
@IBOutlet weak var invoiceAmount: UITextField!
@IBOutlet weak var invoiceComment: UITextField!
@IBOutlet weak var amountStepper: UIStepper!
@IBOutlet weak var receivePaymentAddress: UITextView!
@IBOutlet weak var generateInvoiceBtn: UIButton!
@IBOutlet weak var cancelReceiveBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
viewModel.getInfo()
title = "Payments"
tableView.delegate = self
tableView.dataSource = self
selectedListControl.selectedSegmentIndex == 0 ? viewModel.listPayments() : viewModel.listInvoices()
}
override func viewModelDidLoad() {
viewModel.invoices.observe = { [weak self] invoices in
self?.tableView.reloadData()
}
viewModel.payments.observe = { [weak self] payments in
self?.tableView.reloadData()
}
viewModel.channelBalance.observe = { [weak self] balance in
self?.localBalanceValue.text = String(balance)
}
viewModel.walletBalance.observe = { [weak self] walletBalance in
self?.walletBalanceValue.text = String(walletBalance.total)
}
viewModel.isLoading.observe = { [weak self] isLoading in
self?.viewModel.updateBalance()
}
viewModel.paymentInfo.observe = { [weak self] paymentInfo in
if let paymentInfo = paymentInfo{
self?.paymentInfoStack.isHidden = false
self?.payBtn.isHidden = false
self?.paymentInfoLbl.text = String(paymentInfo.numSatoshis)
self?.paymentInfoCreated.text = paymentInfo.timestamp.getAsDate().format(style: .medium)
self?.paymentInfoExpiry.text = String(paymentInfo.timestamp.getAsDate().adding(seconds: Int(paymentInfo.expiry)).format(style: .medium))
self?.memoLbl.text = String(paymentInfo.description_p)
}else{
self?.paymentInfoStack.isHidden = true
self?.payBtn.isHidden = true
self?.paymentInfoCreated.text = ""
self?.paymentInfoLbl.text = ""
self?.paymentInfoExpiry.text = ""
self?.memoLbl.text = ""
}
}
viewModel.load()
}
//MARK: - Selection
@IBAction func didChangeSelection(_ sender: Any) {
selectedListControl.selectedSegmentIndex == 0 ? viewModel.listPayments() : viewModel.listInvoices()
tableView.reloadData()
}
@IBAction func didPressCancel(_ sender: Any) {
showHideViews(isSending: !sendStackView.isHidden, isFinished: true)
}
//MARK: - Send
@IBAction func didPressSend(_ sender: Any) {
sendPaymentAddress.text = "Input Address ..."
sendPaymentAddress.textColor = UIColor.lightGray
sendPaymentAddress.delegate = self
sendPaymentAddress.layer.borderColor = UIColor.lightGray.cgColor
sendPaymentAddress.layer.borderWidth = 1
showHideViews(isSending: true, isFinished: false)
}
@IBAction func didPressScan(_ sender: Any) {
// Create an instance of QRCodeScanViewController
let viewController = QRCodeScanViewController.create()
// Set itself as delegate
viewController.delegate = self
// Present the view controller
self.present(viewController, animated: true)
}
@IBAction func didPressPay(_ sender: Any) {
self.selectedListControl.selectedSegmentIndex = 0
self.selectedListControl.sendActions(for: .valueChanged)
if let paymentAddress = sendPaymentAddress.text{
debugPrint("Invoice ", paymentAddress)
self.viewModel.payInvoice(invoice: paymentAddress) { response in
self.showAlert(title: "Payment", errorMsg: "Payment Request Sent")
} onFailure: { error in
self.showAlert(title: "Payment", errorMsg: error.debugDescription)
}
self.showAlert(title: "Payment", errorMsg: "Payment Request Sent")
}else{
self.showAlert(title: "Payment", errorMsg: "Payment Request Failed")
}
showHideViews(isSending: true, isFinished: true)
}
//MARK: - Receive
@IBAction func didPressReceive(_ sender: Any) {
invoiceComment.delegate = self
invoiceAmount.delegate = self
showHideViews(isSending: false, isFinished: false)
}
@IBAction func didUpdateStepper(_ sender: UIStepper) {
invoiceAmount.text = String(String(format: "%.f", sender.value))
estimateFeeValue.text = String(String(format: "%.2f", sender.value/1000))
generateInvoiceBtn.isHidden = false
}
@IBAction func didPressGenerateBtn(_ sender: Any) {
self.selectedListControl.selectedSegmentIndex = 1
self.selectedListControl.sendActions(for: .valueChanged)
guard let amountText = invoiceAmount.text else{
self.showAlert(title: "Invoice", errorMsg: "Empty Amount")
return
}
debugPrint("", amountText)
guard let amount:Int = Int(amountText) else{
self.showAlert(title: "Invoice", errorMsg: "Invalid Amount")
return
}
guard let balance:Int = viewModel.walletBalance.value?.total else {
self.showAlert(title: "Invoice", errorMsg: "Invalid wallet balance")
return
}
if(amount > balance){
self.showAlert(title: "Invoice", errorMsg: "Insufficient funds")
}else if amount == 0{
self.showAlert(title: "Invoice", errorMsg: "No amount selected")
}else{
createInvoice(amount: amount, comment: invoiceComment.text ?? "")
}
showHideViews(isSending: false, isFinished: true)
}
func showHideViews(isSending: Bool, isFinished: Bool){
sendStackView.isHidden = isFinished || (!isFinished && !isSending)
receiveStackView.isHidden = isFinished || (!isFinished && isSending)
feeStackView.isHidden = isFinished || (!isFinished && isSending)
paymentButtonsStack.isHidden = !isFinished
tableView.isHidden = !isFinished
selectedListControl.isHidden = !isFinished
generateInvoiceBtn.isHidden = true
payBtn.isHidden = true
if isFinished{
invoiceComment.text = ""
invoiceAmount.text = "0"
estimateFeeValue.text = "0"
sendPaymentAddress.text = ""
}
}
}
//MARK: - Create Invoice
extension PaymentsVC{
func createInvoice(amount: Int, comment: String){
self.showLoadingView()
viewModel.createInvoice(amount: amount, comment: comment) { paymentRequest in
self.showContentView()
self.showAlert(title: "Invoice", address: paymentRequest)
} onFailure: { error in
self.showContentView()
self.showAlert(title: "Invoice", errorMsg: error.debugDescription)
}
}
}
extension PaymentsVC: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
emptyLabel.text = ""
emptyLabel.textAlignment = NSTextAlignment.center
self.tableView.backgroundView = emptyLabel
if selectedListControl.selectedSegmentIndex == 0{
if let noOfPayments = viewModel.payments.value?.count{
return noOfPayments
}else{
emptyLabel.text = "No Payments"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
}else{
if let noOfInvoices = viewModel.invoices.value?.count{
return noOfInvoices
}else{
emptyLabel.text = "No Invoices"
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let reuseCellIdentifier = "cellIdentifier"
var cell = tableView.dequeueReusableCell(withIdentifier: reuseCellIdentifier)
if (!(cell != nil)) {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: reuseCellIdentifier)
}
cell?.textLabel?.numberOfLines = 0
cell?.detailTextLabel?.numberOfLines = 0
if selectedListControl.selectedSegmentIndex == 0{
if let payment = viewModel.payments.value?[indexPath.row]{
cell?.textLabel?.text = "Status: \(payment.status) \nAmount: \(payment.value) sat"
cell?.detailTextLabel?.text = "\nDate: \(payment.creationDate.getAsDate()) \nFee:\(payment.feeSat) \nPayment hash:\n\(payment.paymentRequest.description)"
}
}else{
if let invoice = viewModel.invoices.value?[indexPath.row]{
cell?.textLabel?.text = "Status: \(invoice.state) \nAmount: \(invoice.value) sat"
cell?.detailTextLabel?.text = "\nDate Created: \(invoice.creationDate.getAsDate()) \nMemo:\(invoice.memo) \nPayment request: \(invoice.paymentRequest)"
}
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedListControl.selectedSegmentIndex == 0{
if let payment = viewModel.payments.value?[indexPath.row]{
UIPasteboard.general.string = payment.paymentRequest.description
}
}else{
if let invoice = viewModel.invoices.value?[indexPath.row]{
self.showAlert(title: "Invoice", address: invoice.paymentRequest)
}
}
}
}
extension PaymentsVC: UITextFieldDelegate{
/**
* Called when 'return' key pressed. return NO to ignore.
*/
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if !(invoiceAmount.text?.isEmpty ?? true){
generateInvoiceBtn.isHidden = false
}
textField.resignFirstResponder()
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == invoiceAmount{
let allowedCharacters = CharacterSet.decimalDigits
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
}
return true
}
/**
* Called when the user click on the view (outside the UITextField).
*/
func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
}
extension PaymentsVC: UITextPasteDelegate {
func textPasteConfigurationSupporting(_ textPasteConfigurationSupporting: UITextPasteConfigurationSupporting, shouldAnimatePasteOf attributedString: NSAttributedString, to textRange: UITextRange) -> Bool {
return false
}
}
extension PaymentsVC: UITextViewDelegate{
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == UIColor.lightGray {
textView.text = nil
textView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = "Input Address ..."
textView.textColor = UIColor.lightGray
}
}
func textViewDidChange(_ textView: UITextView) {
if(textView.text == UIPasteboard.general.string){
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Combine the textView text and the replacement text to
// create the updated text string
let currentText:String = textView.text
let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)
// If updated text view will be empty, add the placeholder
// and set the cursor to the beginning of the text view
if updatedText.isEmpty {
textView.text = "Input Address ..."
textView.textColor = UIColor.lightGray
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
// Else if the text view's placeholder is showing and the
// length of the replacement string is greater than 0, set
// the text color to black then set its text to the
// replacement string
else if textView.textColor == UIColor.lightGray && !text.isEmpty {
textView.textColor = UIColor.black
textView.text = text
}else if text == "\n" {
textView.resignFirstResponder()
self.viewModel.getPaymentDetail(invoice: textView.text)
return false
}
// For every other case, the text should change with the usual
// behavior...
else {
return true
}
// ...otherwise return false since the updates have already
// been made
return false
}
func textViewDidChangeSelection(_ textView: UITextView) {
if self.view.window != nil {
if textView.textColor == UIColor.lightGray {
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
}
}
}
extension PaymentsVC: QRCodeScanViewControllerDelegate{
// MARK: QRCodeScanViewControllerDelegate
/// Called when the camera scans a QR code
/// - Parameters:
/// - viewController: View controller that scanned the QR code
/// - value: String encoded in the QR code
func qrCodeScanViewController(_ viewController: QRCodeScanViewController, didScanQRCode value: String) {
// Dismiss the view controller
viewController.dismiss(animated: true) {
self.sendPaymentAddress.text = value
self.sendPaymentAddress.tintColor = UIColor.black
self.viewModel.getPaymentDetail(invoice: value)
}
}
}

View File

@ -0,0 +1,504 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_5" orientation="portrait" appearance="dark"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PaymentsVC" customModule="wallet" customModuleProvider="target">
<connections>
<outlet property="amountStepper" destination="T9i-3R-cri" id="acC-86-u4S"/>
<outlet property="cancelPayBtn" destination="U13-IO-hAk" id="hPn-DL-vGM"/>
<outlet property="cancelReceiveBtn" destination="ziL-bN-VuJ" id="kVP-kP-hzc"/>
<outlet property="estimateFeeValue" destination="Iwm-ze-Xdw" id="4AW-WP-rCe"/>
<outlet property="feeStackView" destination="iXB-vl-PMu" id="6nY-oa-oFO"/>
<outlet property="generateInvoiceBtn" destination="PBr-bz-1w7" id="oeA-6E-m9v"/>
<outlet property="invoiceAmount" destination="cEe-CT-RNM" id="PPN-LF-dkX"/>
<outlet property="invoiceComment" destination="cVl-JJ-kdK" id="kAE-jl-WAA"/>
<outlet property="localBalanceValue" destination="5XZ-kK-3vj" id="0kf-Sw-s3H"/>
<outlet property="memoLbl" destination="hpJ-ik-Uk2" id="X8G-aF-5to"/>
<outlet property="payBtn" destination="8yZ-fV-Z9Q" id="J5Q-dP-pBk"/>
<outlet property="paymentButtonsStack" destination="SEY-by-HAH" id="jx2-GO-5RK"/>
<outlet property="paymentElements" destination="L4r-Do-IUm" id="fdZ-gw-OuJ"/>
<outlet property="paymentInfoCreated" destination="biX-qT-Uvp" id="glg-CQ-rRM"/>
<outlet property="paymentInfoExpiry" destination="yvM-6G-jWp" id="Iz9-cq-N7D"/>
<outlet property="paymentInfoLbl" destination="Qwo-Y1-a24" id="swz-pb-L4o"/>
<outlet property="paymentInfoStack" destination="WGx-MS-QY4" id="Be1-Kg-pP3"/>
<outlet property="receiveStackView" destination="MyI-gR-AxB" id="Rsz-yN-qmb"/>
<outlet property="remoteBalanceValue" destination="5wG-S9-P0n" id="q2N-uP-XDu"/>
<outlet property="selectedListControl" destination="Vcc-bu-AMC" id="c0R-WA-Ihu"/>
<outlet property="sendPaymentAddress" destination="K52-8B-0Ky" id="5Wo-ft-rVC"/>
<outlet property="sendStackView" destination="VNJ-zr-pHr" id="wVH-2J-c9a"/>
<outlet property="tableView" destination="0jD-Yd-8Mg" id="YPu-rQ-Ksh"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
<outlet property="walletBalanceValue" destination="7GV-G8-6RM" id="hFw-WK-gcd"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Xai-Q3-vRS" userLabel="Payment Stack">
<rect key="frame" x="10" y="64" width="394" height="788"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="L4r-Do-IUm">
<rect key="frame" x="0.0" y="0.0" width="394" height="198"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="mgZ-Yn-C0m">
<rect key="frame" x="0.0" y="0.0" width="394" height="19.333333333333332"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Wallet Balance:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8CK-SL-j6c">
<rect key="frame" x="0.0" y="0.0" width="321.33333333333331" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7GV-G8-6RM">
<rect key="frame" x="331.33333333333331" y="0.0" width="12.666666666666686" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9yF-Lj-HGL">
<rect key="frame" x="354" y="0.0" width="40" height="19.333333333333332"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="Yst-ng-iXy"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="yhP-LX-kWu">
<rect key="frame" x="0.0" y="29.333333333333329" width="394" height="19.333333333333329"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Local Balance:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3qv-zE-MGq">
<rect key="frame" x="0.0" y="0.0" width="321.33333333333331" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5XZ-kK-3vj">
<rect key="frame" x="331.33333333333331" y="0.0" width="12.666666666666686" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="N5R-zX-pSx">
<rect key="frame" x="354" y="0.0" width="40" height="19.333333333333332"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="WT3-Ht-Fwr"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="N6B-qA-M1m">
<rect key="frame" x="0.0" y="58.666666666666679" width="394" height="19.333333333333336"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Remote Balance:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xNf-Xs-Sca">
<rect key="frame" x="0.0" y="0.0" width="321.33333333333331" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5wG-S9-P0n">
<rect key="frame" x="331.33333333333331" y="0.0" width="12.666666666666686" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4TF-14-eWd">
<rect key="frame" x="354" y="0.0" width="40" height="19.333333333333332"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="nXc-92-f0h"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="iXB-vl-PMu">
<rect key="frame" x="0.0" y="83" width="394" height="0.0"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Fee:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8V9-WT-6A9">
<rect key="frame" x="0.0" y="0.0" width="321.33333333333331" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Iwm-ze-Xdw">
<rect key="frame" x="331.33333333333331" y="0.0" width="12.666666666666686" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3xQ-a7-dyM">
<rect key="frame" x="354" y="0.0" width="40" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="MVZ-TT-Mvc"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="SEY-by-HAH" userLabel="Payment Buttons">
<rect key="frame" x="0.0" y="88" width="394" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gsg-XS-xUI">
<rect key="frame" x="0.0" y="0.0" width="192" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="E1b-s2-U3t"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Send" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressSend:" destination="-1" eventType="touchUpInside" id="pQB-sp-4HT"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1kb-AC-orN">
<rect key="frame" x="202" y="0.0" width="192" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Receive" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressReceive:" destination="-1" eventType="touchUpInside" id="KOA-VA-c0a"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RNs-xK-8tN">
<rect key="frame" x="0.0" y="138" width="394" height="60"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="HRH-3l-Ykt">
<rect key="frame" x="10" y="10" width="374" height="40"/>
<subviews>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="VNJ-zr-pHr" userLabel="send">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="210"/>
<subviews>
<textView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" keyboardDismissMode="interactive" textAlignment="natural" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="K52-8B-0Ky">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="150"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="150" id="bFa-P4-AuL"/>
</constraints>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="12"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" enablesReturnKeyAutomatically="YES" smartDashesType="no" smartQuotesType="no"/>
</textView>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="WGx-MS-QY4">
<rect key="frame" x="0.0" y="155" width="285.66666666666669" height="15"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Tac-1T-QSD">
<rect key="frame" x="0.0" y="0.0" width="131.66666666666666" height="0.0"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Amount:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="67Y-cj-4UK">
<rect key="frame" x="0.0" y="0.0" width="70" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="70" id="CZT-dH-IUx"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qwo-Y1-a24">
<rect key="frame" x="80" y="0.0" width="12.666666666666671" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Iqx-qF-g4z">
<rect key="frame" x="102.66666666666667" y="0.0" width="29.000000000000014" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="svR-IM-B0c">
<rect key="frame" x="0.0" y="5" width="120" height="0.0"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Memo:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="57B-x0-587">
<rect key="frame" x="0.0" y="0.0" width="60" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="uwf-X1-6X0"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hpJ-ik-Uk2">
<rect key="frame" x="70" y="0.0" width="50" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="HYH-Kg-BVn">
<rect key="frame" x="0.0" y="10" width="160" height="0.0"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Created at:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0o5-97-tmh">
<rect key="frame" x="0.0" y="0.0" width="100" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="lly-03-g64"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="biX-qT-Uvp">
<rect key="frame" x="110" y="0.0" width="50" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="18"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="aeg-eq-JkP">
<rect key="frame" x="0.0" y="15" width="160" height="0.0"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Expires at:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dfn-1O-d7Q">
<rect key="frame" x="0.0" y="0.0" width="100" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="cLy-eY-6cd"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yvM-6G-jWp">
<rect key="frame" x="110" y="0.0" width="50" height="0.0"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="18"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="1Ve-gj-DTh">
<rect key="frame" x="0.0" y="160" width="285.66666666666669" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="K7J-kG-4Zh" userLabel="Info">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<buttonConfiguration key="configuration" style="filled" title="Scan" cornerStyle="capsule">
<imageReference key="image" image="qrcode" catalog="system" symbolScale="medium"/>
<preferredSymbolConfiguration key="preferredSymbolConfigurationForImage" configurationType="pointSize" pointSize="20" scale="large" weight="semibold"/>
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</buttonConfiguration>
<connections>
<action selector="didPressScan:" destination="-1" eventType="touchUpInside" id="R4X-3z-pmw"/>
</connections>
</button>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8yZ-fV-Z9Q">
<rect key="frame" x="0.0" y="5" width="285.66666666666669" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Pay" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressPay:" destination="-1" eventType="touchUpInside" id="Hn3-G1-qHq"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="U13-IO-hAk">
<rect key="frame" x="0.0" y="10" width="285.66666666666669" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Fnb-yO-R5y"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Cancel" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressCancel:" destination="-1" eventType="touchUpInside" id="dXn-9n-thO"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="MyI-gR-AxB" userLabel="receive">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="45"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalCentering" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="z3t-KC-SNp">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="25"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="0" borderStyle="roundedRect" placeholder="Amount" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="cEe-CT-RNM">
<rect key="frame" x="0.0" y="0.0" width="150" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="1Pj-2G-wMB"/>
<constraint firstAttribute="height" constant="25" id="bKd-8V-HHN"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" wraps="YES" value="100" maximumValue="9.2233720368547758e+18" stepValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="T9i-3R-cri">
<rect key="frame" x="155" y="0.0" width="94" height="25"/>
<connections>
<action selector="didUpdateStepper:" destination="-1" eventType="valueChanged" id="z5d-tw-ZMC"/>
</connections>
</stepper>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sats" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pAl-cD-IYY">
<rect key="frame" x="253.99999999999997" y="0.0" width="31.666666666666657" height="25"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Comment" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="cVl-JJ-kdK">
<rect key="frame" x="0.0" y="35" width="285.66666666666669" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Cto-uA-T1L">
<rect key="frame" x="0.0" y="45" width="285.66666666666669" height="0.0"/>
<subviews>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PBr-bz-1w7">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Z0b-Mk-QPp"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Generate" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressGenerateBtn:" destination="-1" eventType="touchUpInside" id="epK-9J-1ee"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ziL-bN-VuJ">
<rect key="frame" x="0.0" y="0.0" width="285.66666666666669" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Cancel" cornerStyle="medium">
<color key="baseForegroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="baseBackgroundColor" red="0.36654189230000001" green="0.68308699129999995" blue="0.86276882889999995" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</buttonConfiguration>
<connections>
<action selector="didPressCancel:" destination="-1" eventType="touchUpInside" id="nO9-Jz-ets"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="MyI-gR-AxB" firstAttribute="top" secondItem="VNJ-zr-pHr" secondAttribute="top" id="9lN-jD-HfN"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="HRH-3l-Ykt" firstAttribute="top" secondItem="RNs-xK-8tN" secondAttribute="top" constant="10" id="Cl7-op-iJG"/>
<constraint firstAttribute="trailing" secondItem="HRH-3l-Ykt" secondAttribute="trailing" constant="10" id="JFP-9K-BgM"/>
<constraint firstItem="HRH-3l-Ykt" firstAttribute="leading" secondItem="RNs-xK-8tN" secondAttribute="leading" constant="10" id="Kym-PA-1F9"/>
<constraint firstAttribute="bottom" secondItem="HRH-3l-Ykt" secondAttribute="bottom" constant="10" id="eOV-lf-RI0"/>
</constraints>
</view>
</subviews>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lyu-T0-nGv" userLabel="List">
<rect key="frame" x="0.0" y="208" width="394" height="580"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="wtf-8Z-bdx" userLabel="List Stack">
<rect key="frame" x="0.0" y="0.0" width="394" height="580"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="Vcc-bu-AMC">
<rect key="frame" x="0.0" y="0.0" width="394" height="41"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="sES-9u-W0X"/>
</constraints>
<segments>
<segment title="Payments"/>
<segment title="Invoices"/>
</segments>
<connections>
<action selector="didChangeSelection:" destination="-1" eventType="valueChanged" id="SHG-tw-x2o"/>
</connections>
</segmentedControl>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" estimatedSectionHeaderHeight="-1" sectionFooterHeight="18" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="0jD-Yd-8Mg">
<rect key="frame" x="0.0" y="50" width="394" height="530"/>
</tableView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="wtf-8Z-bdx" firstAttribute="leading" secondItem="lyu-T0-nGv" secondAttribute="leading" id="8SA-T0-q0T"/>
<constraint firstItem="wtf-8Z-bdx" firstAttribute="top" secondItem="lyu-T0-nGv" secondAttribute="top" id="alN-m4-3Nr"/>
<constraint firstAttribute="bottom" secondItem="wtf-8Z-bdx" secondAttribute="bottom" id="lCZ-4p-r9M"/>
<constraint firstAttribute="trailing" secondItem="wtf-8Z-bdx" secondAttribute="trailing" id="qwW-6L-a3y"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="lyu-T0-nGv" firstAttribute="top" secondItem="L4r-Do-IUm" secondAttribute="bottom" constant="10" id="dI9-C9-v9e"/>
</constraints>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="Xai-Q3-vRS" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="20" id="0eZ-ap-g4i"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="Xai-Q3-vRS" secondAttribute="bottom" constant="10" id="S5g-7w-Mch"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Xai-Q3-vRS" secondAttribute="trailing" constant="10" id="bOe-13-CQQ"/>
<constraint firstItem="Xai-Q3-vRS" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="10" id="vLe-6j-pRa"/>
</constraints>
<point key="canvasLocation" x="137.68115942028987" y="81.696428571428569"/>
</view>
</objects>
<resources>
<image name="qrcode" catalog="system" width="128" height="114"/>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View File

@ -0,0 +1,33 @@
//
// ChannelsViewModel.swift
// wallet
//
// Created by Adriana Epure on 23.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
import Foundation
class ChannelsViewModel: ViewModel {
private let exampleRepo = ExampleRepository()
let randomInt = Observable<Int>()
let error = Observable<Error>()
let resultMessage = Observable<String>()
//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"
// private let invoice = "lnbcrt1u1p04e4cypp5qyxj3u8dm2pjsdang94lj6c0d9p33l05999945atjrfyw0nle0ssdqqcqzpgsp5dqlzsd63a0akx9wgv8v9scryj3gn7fe3s8ca9l26s9tjlwkvtv4q9qy9qsq4kv825h86yummfcerkvctfh8c4aw6vc0r986dsyjtp6dun5ysurq2zh0nj6qd4cuf5qskpn9pwre5u26ncce4qy3ataw88p6j08y0xcqy4uxa7"
}

View File

@ -0,0 +1,14 @@
//
// HomeViewModel.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class HomeViewModel: ViewModel {
}

View File

@ -0,0 +1,40 @@
//
// PaymentsViewModel.swift
// wallet
//
// Created by Adriana Epure on 22.08.2022.
// Copyright © 2022 Jason. All rights reserved.
//
class PaymentsViewModel: ViewModel {
let paymentInfo = Observable<Lnrpc_PayReq?>()
func updateBalance(){
self.getWalletBalance()
self.getChannelBalance()
}
func getPaymentDetail(invoice: String){
self.getPaymentInfo(invoice: invoice) { payment in
self.paymentInfo.value = payment
} onFailure: { error in
self.paymentInfo.value = nil
}
}
func sendPayment(invoice: String, completion: @escaping (String) -> Void) {
self.payInvoice(invoice: invoice) { response in
self.listPayments()
self.updateBalance()
debugPrint(response.paymentRoute.totalAmt, response.paymentRoute.totalFees, response.paymentError.debugDescription)
} onFailure: { error in
}
}
}

View File

@ -0,0 +1,26 @@
//
// RequestViewModel.swift
// wallet
//
// Created by Jason on 8/30/20.
// Copyright © 2020 Jason. All rights reserved.
//
import Foundation
class RequestViewModel: ViewModel {
let amount = Observable<Double>()
let note = Observable<String?>()
let invoice = Observable<String>()
// TODO: Add the proper repo or values in here to handle creating the lnd invoice
func createInvoice() {
let example = "lightning:lnbcrt5u1pdam80cpp5hrx4jp3hwe0vrl3jyft95fnfvgsvc327xw5j63mfchc6nazl87csdphf35kw6r5wahhy6eqx43xgepev3jkxctyxumrjdrxxqmn2ctrve3njvscqzys9htkyg7r5kesumuhkntta8syzc2uclqj2lrq5spwppa2r4d2dm49pkhpjemjp3rrm0se4cmakcqgrakpk9hlnv2mgj3dus3yujfzhqsqa7satk"
invoice.value = example
}
}

View File

@ -0,0 +1,318 @@
//
// 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<String>()
private let exampleRepo = ExampleRepository()
let isLoading = Observable<Bool>()
let lightningRepo = LightningRepository()
let walletWipe = Observable<Void>()
let walletBalance = Observable<WalletBalance>()
let channelBalance = Observable<Int>()
let lndInfo = Observable<Lnrpc_GetInfoResponse>()
let channels = Observable<[Lnrpc_Channel]>()
let closedChannels = Observable<[Lnrpc_ChannelCloseSummary]>()
let pendingChannels = Observable<Lnrpc_PendingChannelsResponse>()
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)
}
}
}

View File

@ -0,0 +1,59 @@
import UIKit
class CustomButton: UIButton {
@objc private var action: () -> Void
private var didSetCorners = false
private let label = UILabel()
var title: String? {
get {
return label.text
}
set(newTitle) {
label.text = newTitle?.uppercased()
}
}
init(action: @escaping () -> Void) {
self.action = action
super.init(frame: .zero)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
backgroundColor = Theme.primaryColor
clipsToBounds = true
addLabel()
addTapRecognizer()
}
private func addTapRecognizer() {
let tap = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
addGestureRecognizer(tap)
}
@objc private func tap(_ sender: UITapGestureRecognizer) {
self.action()
}
private func addLabel() {
label.textColor = .gray900
label.textAlignment = .center
label.font = Fonts.sofiaPro(weight: .regular, Dimens.normalText)
self.addSubviewAndFill(label, top: 2.0, leading: CGFloat(Dimens.mediumMargin), trailing: -CGFloat(Dimens.mediumMargin))
}
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
if (!didSetCorners) {
didSetCorners = true
layer.cornerRadius = frame.height / 2
}
}
}

View File

@ -0,0 +1,39 @@
//
// ErrorView.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
class ErrorView: UIView {
var title: String? {
get {
return label.text
}
set(newTitle) {
label.text = newTitle
}
}
private lazy var label: UILabel = {
let label = UILabel()
label.textColor = Theme.inverseBackgroundColor
label.textAlignment = .center
return UILabel()
}()
init() {
super.init(frame: .zero)
backgroundColor = Theme.backgroundColor
addSubviewAndFill(label)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,29 @@
//
// LoadingView.swift
// wallet
//
// Created by Jason on 8/23/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
class LoadingView: UIView {
init() {
super.init(frame: .zero)
backgroundColor = Theme.backgroundColor
addLoadingIndicator()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func addLoadingIndicator() {
let loadingIndicator = UIActivityIndicatorView(style: .large)
self.addSubviewAndFill(loadingIndicator)
loadingIndicator.startAnimating()
}
}

View File

@ -0,0 +1,40 @@
//
// NumberPad.swift
// wallet
//
// Created by Jason on 8/30/20.
// Copyright © 2020 Jason. All rights reserved.
//
import UIKit
class CheddarNumberPad: UIView {
@objc private var onItemClicked: (String) -> Void
@objc private var onBackspaceClicked: () -> Void
init(onItemClicked: @escaping (String) -> Void, onBackspaceClicked: @escaping () -> Void) {
self.onItemClicked = onItemClicked
self.onBackspaceClicked = onBackspaceClicked
super.init(frame: .zero)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
backgroundColor = Theme.shadowColor
}
private func createButtons() {
// Create 1 to 9
for i in 1...10 {
print(i)
}
}
}

View File

@ -0,0 +1,23 @@
/*
Localizable.strings
wallet
Created by Jason on 8/23/20.
Copyright © 2020 Jason. All rights reserved.
*/
"REQUEST" = "Request";
"NOTE" = "Note";
"NEXT" = "Next";
"FOR" = "For";
"NOTE_PLACEHOLDER" = "Write a message";
"CREATE_QR" = "Create QR Code";
"DEFAULT_ERROR" = "An error occured";
//LND errors
"LND_ERROR_UNKNOWN" = "An error unknown occured";
"LND_ERROR_MAPPING" = "An error unknown occured";
"LND_ERROR_INVALID_PASSWORD" = "Invalid wallet password";
"LND_ERROR_PAYMENT" = "Payment error (%@)";

View File

@ -0,0 +1,6 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "../Lndmobile.framework/Headers/Lndmobile.h"

View File

@ -0,0 +1,6 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "../Lndmobile.framework/Headers/Lndmobile.h"