Skip to content

Commit f4ecc80

Browse files
committed
WIP
1 parent b129ce0 commit f4ecc80

7 files changed

Lines changed: 93 additions & 66 deletions

File tree

phoenix-ios/phoenix-ios/officers/BusinessManager.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ class BusinessManager {
206206

207207
log.debug("eventsFlowPublisher(B): event: \(event)")
208208

209-
if let msg = event as? Lightning_kmp_coreCardRequestReceived {
210-
log.debug("found event: CardRequestReceived")
209+
if let msg = event as? Lightning_kmp_corePaymentRequestReceived {
210+
log.debug("found event: PaymentRequestReceived")
211211

212212
if let cardRequest = CardRequest.fromOnionMessage(msg) {
213213
Task { @MainActor in
@@ -797,19 +797,19 @@ class BusinessManager {
797797
return
798798
}
799799

800-
let paymentId = Lightning_kmpUUID.companion.randomUUID()
801-
do {
802-
try await peer.betterPayOffer(
803-
paymentId: paymentId,
804-
amount: cardRequest.amount,
805-
offer: cardRequest.offer,
806-
payerKey: Lightning_randomKey(),
807-
payerNote: nil,
808-
fetchInvoiceTimeoutInSeconds: 30
809-
)
810-
} catch {
811-
log.error("peer.payOffer(): error: \(error)")
812-
}
800+
// let paymentId = Lightning_kmpUUID.companion.randomUUID()
801+
// do {
802+
// try await peer.betterPayOffer(
803+
// paymentId: paymentId,
804+
// amount: cardRequest.amount,
805+
// offer: cardRequest.offer,
806+
// payerKey: Lightning_randomKey(),
807+
// payerNote: nil,
808+
// fetchInvoiceTimeoutInSeconds: 30
809+
// )
810+
// } catch {
811+
// log.error("peer.payOffer(): error: \(error)")
812+
// }
813813
}
814814
}
815815
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ extension DetailsInfoGrid {
666666
identifier: #function,
667667
keyColumnTitle: "Offer"
668668
) {
669-
let text = invoice.invoiceRequest.offer.encode()
669+
let text = invoice.offer.encode()
670670
Text(text)
671671
.lineLimit(5)
672672
.truncationMode(.tail)

phoenix-ios/phoenix-ios/views/receive/LightningDualView.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ struct LightningDualView: View {
743743
// MARK: Tasks
744744
// --------------------------------------------------
745745

746+
@MainActor
746747
func generateQrCode() async {
747748

748749
do {
@@ -1516,8 +1517,14 @@ struct LightningDualView: View {
15161517

15171518
Task { @MainActor in
15181519
do {
1519-
let tuple: KotlinPair<Lightning_kmpOfferTypesOffer, Bitcoin_kmpByteVector32> =
1520-
try await peer.requestCardPayment(
1520+
// let tuple: KotlinPair<Lightning_kmpOfferTypesOffer, Bitcoin_kmpByteVector32> =
1521+
// try await peer.requestCardPayment(
1522+
// amount: msat,
1523+
// cardHolderOffer: bolt12Offer.offer,
1524+
// cardParams: cardParams
1525+
// )
1526+
let tuple: KotlinPair<Lightning_kmpBolt12Invoice, Bitcoin_kmpByteVector32> =
1527+
try await peer.requestCardPayment2(
15211528
amount: msat,
15221529
cardHolderOffer: bolt12Offer.offer,
15231530
cardParams: cardParams

phoenix-ios/phoenix-ios/withdraw/CardRequest.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import PhoenixShared
44
struct CardRequest {
55
let piccData: Data
66
let cmac: Data
7-
let offer: Lightning_kmpOfferTypesOffer
7+
let invoice: Lightning_kmpBolt12Invoice
88
let amount: Lightning_kmpMilliSatoshi
99

10-
static func fromOnionMessage(_ msg: Lightning_kmp_coreCardRequestReceived) -> CardRequest? {
10+
static func fromOnionMessage(_ msg: Lightning_kmp_corePaymentRequestReceived) -> CardRequest? {
1111

1212
var piccStr: String? = nil
1313
var cmacStr: String? = nil
@@ -39,8 +39,8 @@ struct CardRequest {
3939
cmacData = Data(fromHex: cmacStr)
4040
}
4141

42-
if let piccData, let cmacData, let amount = msg.offer.amount {
43-
return CardRequest(piccData: piccData, cmac: cmacData, offer: msg.offer, amount: amount)
42+
if let piccData, let cmacData, let amount = msg.invoice.amount {
43+
return CardRequest(piccData: piccData, cmac: cmacData, invoice: msg.invoice, amount: amount)
4444
} else {
4545
return nil
4646
}
@@ -50,7 +50,7 @@ struct CardRequest {
5050
return WithdrawRequest(
5151
piccData: self.piccData,
5252
cmac: self.cmac,
53-
method: .bolt12Offer(offer: self.offer),
53+
method: .bolt12Invoice(invoice: self.invoice),
5454
amount: self.amount
5555
)
5656
}

phoenix-ios/phoenix-ios/withdraw/WithdrawRequest.swift

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ struct WithdrawRequest {
4949

5050
enum WithdrawRequestMethod {
5151
case bolt11Invoice(invoice: Lightning_kmpBolt11Invoice)
52-
case bolt12Offer(offer: Lightning_kmpOfferTypesOffer)
52+
case bolt12Invoice(invoice: Lightning_kmpBolt12Invoice)
5353

5454
func encode() -> String {
5555
switch self {
5656
case .bolt11Invoice(let invoice):
5757
return invoice.write()
5858

59-
case .bolt12Offer(let offer):
60-
return offer.encode()
59+
case .bolt12Invoice(let invoice):
60+
return invoice.write()
6161
}
6262
}
6363

@@ -66,8 +66,8 @@ enum WithdrawRequestMethod {
6666
case .bolt11Invoice(let invoice):
6767
return invoice.description_
6868

69-
case .bolt12Offer(let offer):
70-
return offer.description_
69+
case .bolt12Invoice(let invoice):
70+
return invoice.description_
7171
}
7272
}
7373
}
@@ -99,7 +99,7 @@ enum WithdrawRequestError: Error, CustomStringConvertible {
9999
case .frozenCard : return "frozen card"
100100
case .dailyLimitExceeded : return "daily limit exceeded"
101101
case .monthlyLimitExceeded : return "monthly limit exceeded"
102-
case .badInvoice : return "bad invoice"
102+
case .badInvoice(_, let details) : return "bad invoice: \(details)"
103103
case .alreadyPaidInvoice : return "already paid invoice"
104104
case .paymentPending : return "payment pending"
105105
case .internalError(_, let details) : return "internal error: \(details)"
@@ -218,30 +218,31 @@ extension PhoenixBusiness {
218218
// Step 4 of 7:
219219
// Validate the invoice.
220220
//
221-
// We know the invoice is a proper Bolt 11 invoice.
222-
// But the SendManager performs additional checks such as:
223-
// - chain mismatch
221+
// We know the invoice is technically valid (not malformed),
222+
// but there are additional checks we need to perform such as:
223+
//
224+
// - chain mismatch (e.g. invoice is for mainnet but we're on testnet)
224225
// - invoice is expired
225226
// - already paid invoice
226227
// - invoice has payment pending
227228
//
228-
// So we use the SendManager to perform those checks.
229-
//
230-
// Note that we already know the input is Bolt11 invoice,
231-
// so we know which route it will take thru the parser.
229+
// The SendManager has standardized code to perform these checks.
232230

233231
do {
234-
let result: SendManager.ParseResult =
235-
try await self.sendManager.parse(
236-
request: request.method.encode(),
237-
progress: { _ in /* ignore */ }
238-
)
232+
let badRequestReason: SendManager.BadRequestReason?
239233

240-
switch onEnum(of: result) {
241-
case .badRequest(let badRequest):
242-
log.debug("SendManager.ParseResult = BadRequest: \(badRequest)")
234+
switch request.method {
235+
case .bolt11Invoice(let invoice):
236+
badRequestReason = try await self.sendManager.checkForBadBolt11Invoice(invoice: invoice)
243237

244-
switch onEnum(of: badRequest.reason) {
238+
case .bolt12Invoice(let invoice):
239+
badRequestReason = try await self.sendManager.checkForBadBolt12Invoice(invoice: invoice)
240+
}
241+
242+
if let badRequestReason {
243+
log.debug("SendManager.BadRequestReason: \(badRequestReason)")
244+
245+
switch onEnum(of: badRequestReason) {
245246
case .alreadyPaidInvoice(_):
246247
return await asyncDeferred(.failure(.alreadyPaidInvoice(card: matchingCard)))
247248

@@ -257,14 +258,11 @@ extension PhoenixBusiness {
257258
default:
258259
return await asyncDeferred(.failure(.badInvoice(card: matchingCard, details: "parse error")))
259260
}
260-
261-
case .success(_):
262-
log.debug("SendManager.ParseResult = Success")
263261
}
264262

265263
} catch {
266-
log.error("SendManager.parse(): threw error: \(error)")
267-
return await asyncDeferred(.failure(.internalError(card: matchingCard, details: "parse error")))
264+
log.error("SendManager.checkForBadBolt1XInvoice: threw error: \(error)")
265+
return await asyncDeferred(.failure(.internalError(card: matchingCard, details: "validation error")))
268266
}
269267

270268
// Step 5 of 7:

phoenix-ios/phoenix-notifySrvExt/NotificationService.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,8 @@ class NotificationService: UNNotificationServiceExtension {
472472
.flatMap { $0.eventsFlowPublisher() }
473473
.sink { (event: Lightning_kmpPeerEvent) in
474474

475-
if let msg = event as? Lightning_kmp_coreCardRequestReceived {
476-
log.debug("found event: CardRequestReceived")
475+
if let msg = event as? Lightning_kmp_corePaymentRequestReceived {
476+
log.debug("found event: PaymentRequestReceived")
477477

478478
if let cardRequest = CardRequest.fromOnionMessage(msg) {
479479
Task { @MainActor in
@@ -563,18 +563,18 @@ class NotificationService: UNNotificationServiceExtension {
563563

564564
// Send the payment
565565
let paymentId = Lightning_kmpUUID.companion.randomUUID()
566-
do {
567-
try await peer.betterPayOffer(
568-
paymentId: paymentId,
569-
amount: cardRequest.amount,
570-
offer: cardRequest.offer,
571-
payerKey: Lightning_randomKey(),
572-
payerNote: nil,
573-
fetchInvoiceTimeoutInSeconds: 30
574-
)
575-
} catch {
576-
log.error("peer.betterPayOffer(): error: \(error)")
577-
}
566+
// do {
567+
// try await peer.betterPayOffer(
568+
// paymentId: paymentId,
569+
// amount: cardRequest.amount,
570+
// offer: cardRequest.offer,
571+
// payerKey: Lightning_randomKey(),
572+
// payerNote: nil,
573+
// fetchInvoiceTimeoutInSeconds: 30
574+
// )
575+
// } catch {
576+
// log.error("peer.betterPayOffer(): error: \(error)")
577+
// }
578578

579579
// Wait for the outgoing payment to complete
580580
business.paymentsManager.lastCompletedPaymentPublisher().sink { payment in

phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/managers/SendManager.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fr.acinq.phoenix.managers
22

33
import fr.acinq.bitcoin.BitcoinError
4+
import fr.acinq.bitcoin.ByteVector32
45
import fr.acinq.bitcoin.Chain
56
import fr.acinq.bitcoin.utils.Either
67
import fr.acinq.lightning.Lightning
@@ -12,6 +13,7 @@ import fr.acinq.lightning.logging.LoggerFactory
1213
import fr.acinq.lightning.logging.debug
1314
import fr.acinq.lightning.logging.error
1415
import fr.acinq.lightning.payment.Bolt11Invoice
16+
import fr.acinq.lightning.payment.Bolt12Invoice
1517
import fr.acinq.lightning.utils.UUID
1618
import fr.acinq.lightning.utils.currentTimestampSeconds
1719
import fr.acinq.lightning.wire.OfferTypes
@@ -196,7 +198,7 @@ class SendManager(
196198
)
197199
}
198200

199-
private suspend fun checkForBadBolt11Invoice(
201+
suspend fun checkForBadBolt11Invoice(
200202
invoice: Bolt11Invoice
201203
): BadRequestReason? {
202204

@@ -209,8 +211,28 @@ class SendManager(
209211
return BadRequestReason.Expired(invoice.timestampSeconds, invoice.expirySeconds ?: Bolt11Invoice.DEFAULT_EXPIRY_SECONDS.toLong())
210212
}
211213

214+
return checkPaymentHash(invoice.paymentHash)
215+
}
216+
217+
suspend fun checkForBadBolt12Invoice(
218+
invoice: Bolt12Invoice
219+
): BadRequestReason? {
220+
221+
val actualChain = invoice.chain
222+
if (chain != actualChain) {
223+
return BadRequestReason.ChainMismatch(expected = chain)
224+
}
225+
226+
if (invoice.isExpired(currentTimestampSeconds())) {
227+
return BadRequestReason.Expired(invoice.createdAtSeconds, invoice.relativeExpirySeconds)
228+
}
229+
230+
return checkPaymentHash(invoice.paymentHash)
231+
}
232+
233+
private suspend fun checkPaymentHash(paymentHash: ByteVector32): BadRequestReason? {
212234
val db = databaseManager.databases.filterNotNull().first()
213-
val similarPayments = db.payments.listLightningOutgoingPayments(invoice.paymentHash)
235+
val similarPayments = db.payments.listLightningOutgoingPayments(paymentHash)
214236
// we MUST raise an error if this payment hash has already been paid, or is being paid.
215237
// parallel pending payments on the same payment hash can trigger force-closes
216238
// FIXME: this check should be done in lightning-kmp, not in Phoenix

0 commit comments

Comments
 (0)