Skip to content

Commit fee4350

Browse files
committed
BLIP 42 support
1 parent 666cbf2 commit fee4350

File tree

23 files changed

+495
-99
lines changed

23 files changed

+495
-99
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[versions]
2-
lightningkmp = "1.11.0"
2+
lightningkmp = "1.10.9-SNAPSHOT"
33
secp256k1 = "0.21.0" # keep in check with lightning-kmp secp version
44

55
kotlin = "2.2.10"

phoenix-ios/phoenix-ios/Localizable.xcstrings

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8086,6 +8086,9 @@
80868086
}
80878087
}
80888088
}
8089+
},
8090+
"BLIP 42 (DEBUG build only)" : {
8091+
80898092
},
80908093
"Block height" : {
80918094
"localizations" : {
@@ -11624,6 +11627,9 @@
1162411627
}
1162511628
}
1162611629
}
11630+
},
11631+
"contact secret" : {
11632+
1162711633
},
1162811634
"Contact support if needed." : {
1162911635
"localizations" : {
@@ -29316,6 +29322,9 @@
2931629322
}
2931729323
}
2931829324
}
29325+
},
29326+
"payer address" : {
29327+
2931929328
},
2932029329
"Payer key" : {
2932129330
"localizations" : {
@@ -29356,6 +29365,9 @@
2935629365
}
2935729366
}
2935829367
}
29368+
},
29369+
"payer offer" : {
29370+
2935929371
},
2936029372
"Payment" : {
2936129373
"localizations" : {
@@ -34205,6 +34217,9 @@
3420534217
}
3420634218
}
3420734219
}
34220+
},
34221+
"Secrets: (DEBUG build only)" : {
34222+
3420834223
},
3420934224
"Security" : {
3421034225
"extractionState" : "manual",

phoenix-ios/phoenix-ios/kotlin/KotlinExtensions+Lightning.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,7 @@ extension Lightning_kmpPaymentRequest {
4646
extension Lightning_kmpPeer {
4747

4848
var bootChannelsFlowValue: Dictionary<Bitcoin_kmpByteVector32, Lightning_kmpChannelState> {
49-
if let value = self.bootChannelsFlow.value as? Dictionary<Bitcoin_kmpByteVector32, Lightning_kmpChannelState> {
50-
return value
51-
} else {
52-
return [:]
53-
}
49+
return self.bootChannelsFlow.value ?? [:]
5450
}
5551
}
5652

phoenix-ios/phoenix-ios/kotlin/KotlinExtensions+Payments.swift

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ extension WalletPaymentInfo {
132132
var msg: String? = nil
133133

134134
if let incomingOfferMetadata = payment.incomingOfferMetadata() {
135-
msg = incomingOfferMetadata.payerNote
135+
msg = incomingOfferMetadata.payerNote_
136136

137137
} else if let outgoingInvoiceRequest = payment.outgoingInvoiceRequest() {
138138
msg = outgoingInvoiceRequest.payerNote
@@ -165,7 +165,24 @@ extension WalletPaymentInfo {
165165

166166
func addToContactsInfo() -> AddToContactsInfo? {
167167

168-
if payment is Lightning_kmpOutgoingPayment {
168+
if let incoming = payment as? Lightning_kmpIncomingPayment {
169+
170+
if let metadata = payment.incomingOfferMetadata() {
171+
if let rawSecret = metadata.contactSecret_ {
172+
let offer = metadata.payerOffer_
173+
let address = metadata.payerAddress_?.description()
174+
if (offer != nil) || (address != nil) {
175+
let secret = ContactSecret(
176+
id: rawSecret,
177+
incomingPaymentId: incoming.id,
178+
createdAt: Date.now.toMilliseconds()
179+
)
180+
return AddToContactsInfo(offer: offer, address: address, secret: secret)
181+
}
182+
}
183+
}
184+
185+
} else if payment is Lightning_kmpOutgoingPayment {
169186

170187
// First check for a lightning address.
171188
// Remember that an outgoing payment might have both an address & offer (i.e. BIP-353).
@@ -177,12 +194,11 @@ extension WalletPaymentInfo {
177194
// But that's a different feature. The user's perspective remains the same.
178195
//
179196
if let address = self.metadata.lightningAddress {
180-
return AddToContactsInfo(offer: nil, address: address)
197+
return AddToContactsInfo(offer: nil, address: address, secret: nil)
181198
}
182199

183-
let invoiceRequest = payment.outgoingInvoiceRequest()
184-
if let offer = invoiceRequest?.offer {
185-
return AddToContactsInfo(offer: offer, address: nil)
200+
if let offer = payment.outgoingInvoiceRequest()?.offer {
201+
return AddToContactsInfo(offer: offer, address: nil, secret: nil)
186202
}
187203
}
188204

phoenix-ios/phoenix-ios/kotlin/KotlinTypes.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ typealias Lightning_kmpChannelManagementFees = Lightning_kmp_coreChannelManageme
2121
typealias Lightning_kmpChannelState = Lightning_kmp_coreChannelState
2222
typealias Lightning_kmpConnection = Lightning_kmp_coreConnection
2323
typealias Lightning_kmpClosing = Lightning_kmp_coreClosing
24+
typealias Lightning_kmpContactAddress = Lightning_kmp_coreContactAddress
25+
typealias Lightning_kmpContactSecrets = Lightning_kmp_coreContactSecrets
2426
typealias Lightning_kmpDatabases = Lightning_kmp_coreDatabases
2527
typealias Lightning_kmpElectrumClient = Lightning_kmp_coreElectrumClient
2628
typealias Lightning_kmpElectrumMiniWallet = Lightning_kmp_coreElectrumMiniWallet

phoenix-ios/phoenix-ios/views/contacts/AddToContactsInfo.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ import PhoenixShared
44
struct AddToContactsInfo: Hashable {
55
let offer: Lightning_kmpOfferTypesOffer?
66
let address: String?
7+
let secret: ContactSecret?
78
}

phoenix-ios/phoenix-ios/views/contacts/ManageContact.swift

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ struct ManageContact: View {
9898
@State private var editAddress_text: String = ""
9999
@State private var editAddress_invalidReason: InvalidReason? = nil
100100

101+
@State private var secrets: [ContactSecret]
102+
@State private var secrets_hasChanges: Bool
103+
101104
enum FooterType: Int {
102105
case expanded_standard = 1
103106
case expanded_squeezed = 2
@@ -184,7 +187,6 @@ struct ManageContact: View {
184187
hasNewOffer = true
185188
}
186189
}
187-
188190

189191
self._offers = State(initialValue: rows)
190192
self._offers_hasChanges = State(initialValue: (contact != nil && hasNewOffer))
@@ -214,11 +216,34 @@ struct ManageContact: View {
214216
hasNewAddress = true
215217
}
216218
}
217-
218219

219220
self._addresses = State(initialValue: rows)
220221
self._addresses_hasChanges = State(initialValue: (contact != nil && hasNewAddress))
221222
}
223+
do {
224+
var set = Set<Bitcoin_kmpByteVector32>()
225+
var secrets = Array<ContactSecret>()
226+
227+
if let contact {
228+
for secret in contact.secrets {
229+
if !set.contains(secret.id) {
230+
set.insert(secret.id)
231+
secrets.append(secret)
232+
}
233+
}
234+
}
235+
var hasNewSecret = false
236+
if let newSecret = info?.secret {
237+
if !set.contains(newSecret.id) {
238+
set.insert(newSecret.id)
239+
secrets.append(newSecret)
240+
hasNewSecret = true
241+
}
242+
}
243+
244+
self._secrets = State(initialValue: secrets)
245+
self._secrets_hasChanges = State(initialValue: (contact != nil && hasNewSecret))
246+
}
222247
}
223248

224249
// --------------------------------------------------
@@ -397,6 +422,9 @@ struct ManageContact: View {
397422
content_trusted()
398423
content_offers()
399424
content_addresses()
425+
#if DEBUG
426+
content_secrets()
427+
#endif
400428
} // </VStack>
401429
.padding()
402430
} // </ScrollView>
@@ -934,6 +962,67 @@ struct ManageContact: View {
934962
.padding(.top, ROW_VERTICAL_SPACING)
935963
}
936964

965+
@ViewBuilder
966+
func content_secrets() -> some View {
967+
968+
VStack(alignment: HorizontalAlignment.leading, spacing: 0) {
969+
970+
HStack(alignment: VerticalAlignment.center, spacing: 0) {
971+
Text("Secrets: (DEBUG build only)")
972+
Spacer(minLength: 0)
973+
} // </HStack>
974+
975+
VStack(alignment: HorizontalAlignment.leading, spacing: 0) {
976+
ForEach(0 ..< secrets.count, id: \.self) { idx in
977+
content_secret_row(idx)
978+
} // </ForEach>
979+
} // </VStack>
980+
981+
if secrets.isEmpty {
982+
content_secret_emptyRow()
983+
}
984+
985+
} // </VStack>
986+
.padding(.bottom, 30)
987+
}
988+
989+
@ViewBuilder
990+
func content_secret_row(_ index: Int) -> some View {
991+
992+
let row: ContactSecret = secrets[index]
993+
994+
HStack(alignment: VerticalAlignment.firstTextBaseline, spacing: 0) {
995+
996+
bullet()
997+
998+
VStack(alignment: HorizontalAlignment.leading, spacing: 4) {
999+
Text(row.id.toHex())
1000+
.foregroundStyle(Color.primary)
1001+
Text(verbatim: "incomingPaymentId: \( row.incomingPaymentId?.description() ?? "<nil>" )")
1002+
.foregroundStyle(Color.secondary)
1003+
}
1004+
.lineLimit(1)
1005+
.truncationMode(.middle)
1006+
.font(.callout)
1007+
1008+
}
1009+
.padding(.top, ROW_VERTICAL_SPACING)
1010+
}
1011+
1012+
@ViewBuilder
1013+
func content_secret_emptyRow() -> some View {
1014+
1015+
HStack(alignment: VerticalAlignment.firstTextBaseline, spacing: 0) {
1016+
bullet()
1017+
Text("none")
1018+
.lineLimit(1)
1019+
.foregroundStyle(Color.secondary)
1020+
.layoutPriority(-1)
1021+
.font(.callout)
1022+
}
1023+
.padding(.top, ROW_VERTICAL_SPACING)
1024+
}
1025+
9371026
@ViewBuilder
9381027
func bullet() -> some View {
9391028

@@ -1290,7 +1379,7 @@ struct ManageContact: View {
12901379
if doNotUseDiskImage {
12911380
return true
12921381
}
1293-
if offers_hasChanges || addresses_hasChanges {
1382+
if offers_hasChanges || addresses_hasChanges || secrets_hasChanges {
12941383
return true
12951384
}
12961385

@@ -1487,9 +1576,12 @@ struct ManageContact: View {
14871576
photoUri: newPhotoName,
14881577
useOfferKey: updatedUseOfferKey,
14891578
offers: offers.map { $0.raw },
1490-
addresses: addresses.map { $0.raw }
1579+
addresses: addresses.map { $0.raw },
1580+
secrets: secrets
14911581
)
14921582

1583+
log.debug("updatedContact.secrets.count: \(updatedContact.secrets.count)")
1584+
14931585
let contactsDb = try await Biz.business.databaseManager.contactsDb()
14941586

14951587
try await contactsDb.saveContact(contact: updatedContact)

phoenix-ios/phoenix-ios/views/inspect/Details/DetailsInfoGrid+CommonSections.swift

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,88 @@ extension DetailsInfoGrid {
454454
}
455455
}
456456

457+
// --------------------------------------------------
458+
// MARK: Section: BLIP 42
459+
// --------------------------------------------------
460+
#if DEBUG
461+
462+
@ViewBuilder
463+
func section_blip42(
464+
_ secret: Bitcoin_kmpByteVector32?,
465+
_ offer: Lightning_kmpOfferTypesOffer?,
466+
_ address: Lightning_kmp_coreUnverifiedContactAddress?
467+
) -> some View {
468+
469+
InlineSection {
470+
header("BLIP 42 (DEBUG build only)")
471+
} content: {
472+
blip42_contactSecret(secret)
473+
blip42_offer(offer)
474+
blip42_address(address)
475+
}
476+
}
477+
478+
@ViewBuilder
479+
func blip42_contactSecret(
480+
_ secret: Bitcoin_kmpByteVector32?
481+
) -> some View {
482+
483+
detailsRow(
484+
identifier: #function,
485+
keyColumnTitle: "contact secret"
486+
) {
487+
if let str = secret?.toHex() {
488+
Text(str)
489+
.lineLimit(2)
490+
.truncationMode(.middle)
491+
} else {
492+
Text(verbatim: "<null>")
493+
.foregroundStyle(Color.secondary)
494+
}
495+
}
496+
}
497+
498+
@ViewBuilder
499+
func blip42_offer(
500+
_ offer: Lightning_kmpOfferTypesOffer?
501+
) -> some View {
502+
503+
detailsRow(
504+
identifier: #function,
505+
keyColumnTitle: "payer offer"
506+
) {
507+
if let str = offer?.encode() {
508+
Text(str)
509+
.lineLimit(2)
510+
.truncationMode(.middle)
511+
} else {
512+
Text(verbatim: "<null>")
513+
.foregroundStyle(Color.secondary)
514+
}
515+
}
516+
}
517+
518+
@ViewBuilder
519+
func blip42_address(
520+
_ address: Lightning_kmp_coreUnverifiedContactAddress?
521+
) -> some View {
522+
523+
detailsRow(
524+
identifier: #function,
525+
keyColumnTitle: "payer address"
526+
) {
527+
if let str = address?.description() {
528+
Text(str)
529+
.lineLimit(2)
530+
.truncationMode(.middle)
531+
} else {
532+
Text(verbatim: "<null>")
533+
.foregroundStyle(Color.secondary)
534+
}
535+
}
536+
}
537+
538+
#endif
457539
// --------------------------------------------------
458540
// MARK: SubSection: Bolt11 Invoice
459541
// --------------------------------------------------

phoenix-ios/phoenix-ios/views/inspect/Details/Details_Incoming_Bolt12.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ struct Details_Incoming_Bolt12: DetailsInfoGrid {
4343
section_timestamps()
4444
section_incoming()
4545
section_lightningParts(payment)
46+
#if DEBUG
47+
let metadata = payment.metadata
48+
section_blip42(metadata.contactSecret_, metadata.payerOffer_, metadata.payerAddress_)
49+
#endif
4650
}
4751
}
4852
.background(Color.primaryBackground)

0 commit comments

Comments
 (0)