@@ -23,12 +23,23 @@ enum PublicPaykitPaymentLaunchResult {
2323 case opened
2424 case noEndpoint
2525 case notOpened
26+
27+ var contactPaymentFailureMessageKey : String ? {
28+ switch self {
29+ case . opened:
30+ nil
31+ case . noEndpoint:
32+ " slashtags__error_pay_empty_msg "
33+ case . notOpened:
34+ " slashtags__error_pay_not_opened_msg "
35+ }
36+ }
2637}
2738
2839enum PublicPaykitService {
2940 enum MethodId : String , Hashable {
3041 case bitcoinLightningBolt11 = " btc-lightning-bolt11 "
31- case bitcoinLightningLnurl = " btc-lightning-lnurl-pay "
42+ case bitcoinLightningLnurl = " btc-lightning-lnurl "
3243 case bitcoinOnchainP2tr = " btc-bitcoin-p2tr "
3344 case bitcoinOnchainP2wpkh = " btc-bitcoin-p2wpkh "
3445 case bitcoinOnchainP2sh = " btc-bitcoin-p2sh "
@@ -50,6 +61,13 @@ enum PublicPaykitService {
5061 . bitcoinOnchainP2sh,
5162 . bitcoinOnchainP2pkh,
5263 ]
64+
65+ static let onchainPreferenceOrder : [ MethodId ] = [
66+ . bitcoinOnchainP2tr,
67+ . bitcoinOnchainP2wpkh,
68+ . bitcoinOnchainP2sh,
69+ . bitcoinOnchainP2pkh,
70+ ]
5371 }
5472
5573 struct Endpoint : Equatable , Hashable {
@@ -114,7 +132,7 @@ enum PublicPaykitService {
114132 @MainActor
115133 static func syncPublishedEndpoints( wallet: WalletViewModel , publish: Bool ) async throws {
116134 guard publish else {
117- await removePublishedEndpoints ( )
135+ try await removePublishedEndpoints ( )
118136 return
119137 }
120138
@@ -128,12 +146,36 @@ enum PublicPaykitService {
128146 try await applyPublishedEndpoints ( desiredEndpoints)
129147 }
130148
131- static func removePublishedEndpoints( ) async {
132- for methodId in MethodId . publishableMethodIds {
133- try ? await PubkyService . removePaymentEndpoint ( methodId: methodId. rawValue)
149+ static func removePublishedEndpoints( ) async throws {
150+ let existingMethodIds = try await currentPublishedMethodIds ( )
151+
152+ for methodId in MethodId . publishableMethodIds where existingMethodIds. contains ( methodId) {
153+ try await PubkyService . removePaymentEndpoint ( methodId: methodId. rawValue)
134154 }
135155 }
136156
157+ static func hasPayablePublicEndpoint( publicKey: String ) async throws -> Bool {
158+ let endpoints = try await payablePublicEndpoints ( publicKey: publicKey)
159+ return !endpoints. isEmpty
160+ }
161+
162+ static func payablePublicEndpoints( publicKey: String ) async throws -> [ Endpoint ] {
163+ let endpoints = try await fetchPublicEndpoints ( publicKey: publicKey)
164+ return await payableEndpoints ( from: endpoints)
165+ }
166+
167+ static func payableEndpoints( from endpoints: [ Endpoint ] ) async -> [ Endpoint ] {
168+ var payableEndpoints : [ Endpoint ] = [ ]
169+
170+ for endpoint in endpoints {
171+ if await isPayableEndpoint ( endpoint) {
172+ payableEndpoints. append ( endpoint)
173+ }
174+ }
175+
176+ return payableEndpoints
177+ }
178+
137179 @MainActor
138180 static func beginPayment(
139181 to publicKey: String ,
@@ -143,28 +185,65 @@ enum PublicPaykitService {
143185 sheets: SheetViewModel
144186 ) async throws -> PublicPaykitPaymentLaunchResult {
145187 let endpoints = try await fetchPublicEndpoints ( publicKey: publicKey)
188+ let payableEndpoints = await payableEndpoints ( from: endpoints)
146189
147- guard let preferredEndpoint = await preferredPayableEndpoint ( from : endpoints ) else {
190+ guard !payableEndpoints . isEmpty else {
148191 return endpoints. isEmpty ? . noEndpoint : . notOpened
149192 }
150193
151- try await app. handleScannedData ( preferredEndpoint . paymentRequest)
194+ try await app. handleScannedData ( paymentRequest ( from : payableEndpoints ) )
152195
153- guard PaymentNavigationHelper . appropriateSendRoute ( app: app, currency: currency, settings: settings) != nil else {
196+ guard let route = contactPaymentRoute ( app: app, currency: currency, settings: settings) else {
154197 return . notOpened
155198 }
156199
157200 app. contactPaymentContext = ContactPaymentContext ( publicKey: publicKey)
158- PaymentNavigationHelper . openPaymentSheet (
159- app: app,
160- currency: currency,
161- settings: settings,
162- sheetViewModel: sheets
163- )
201+ sheets. showSheet ( . send, data: SendConfig ( view: route) )
164202
165203 return . opened
166204 }
167205
206+ static func paymentRequest( from endpoints: [ Endpoint ] ) -> String {
207+ guard let onchainEndpoint = MethodId . onchainPreferenceOrder. compactMap ( { methodId in endpoints. first { $0. methodId == methodId } } ) . first,
208+ let bolt11Endpoint = endpoints. first ( where: { $0. methodId == . bitcoinLightningBolt11 } )
209+ else {
210+ return endpoints. first? . paymentRequest ?? " "
211+ }
212+
213+ return " bitcoin: \( onchainEndpoint. paymentRequest) ?lightning= \( bolt11Endpoint. paymentRequest) "
214+ }
215+
216+ @MainActor
217+ private static func contactPaymentRoute(
218+ app: AppViewModel ,
219+ currency: CurrencyViewModel ,
220+ settings: SettingsViewModel
221+ ) -> SendRoute ? {
222+ guard let route = PaymentNavigationHelper . appropriateSendRoute ( app: app, currency: currency, settings: settings) else {
223+ return nil
224+ }
225+
226+ switch route {
227+ case . quickpay:
228+ if app. lnurlPayData != nil {
229+ return . lnurlPayAmount
230+ }
231+
232+ if app. scannedLightningInvoice != nil || app. scannedOnchainInvoice != nil {
233+ return . amount
234+ }
235+
236+ return route
237+ case . confirm:
238+ if app. scannedLightningInvoice != nil || app. scannedOnchainInvoice != nil {
239+ return . amount
240+ }
241+ return route
242+ default :
243+ return route
244+ }
245+ }
246+
168247 static func onchainMethodId( for address: String ) -> MethodId {
169248 let normalizedAddress = address. trimmingCharacters ( in: . whitespacesAndNewlines) . lowercased ( )
170249
@@ -220,11 +299,22 @@ enum PublicPaykitService {
220299 )
221300 }
222301
223- for methodId in MethodId . publishableMethodIds where !desiredMethodIds. contains ( methodId) {
224- try ? await PubkyService . removePaymentEndpoint ( methodId: methodId. rawValue)
302+ let existingMethodIds = try await currentPublishedMethodIds ( )
303+
304+ for methodId in MethodId . publishableMethodIds where existingMethodIds. contains ( methodId) && !desiredMethodIds. contains ( methodId) {
305+ try await PubkyService . removePaymentEndpoint ( methodId: methodId. rawValue)
225306 }
226307 }
227308
309+ private static func currentPublishedMethodIds( ) async throws -> Set < MethodId > {
310+ guard let publicKey = await PubkyService . currentPublicKey ( ) else {
311+ throw PubkyServiceError . sessionNotActive
312+ }
313+
314+ let paymentEntries = try await PubkyService . getPaymentList ( publicKey: publicKey)
315+ return Set ( paymentEntries. compactMap { MethodId ( rawValue: $0. methodId) } )
316+ }
317+
228318 @MainActor
229319 private static func buildWalletEndpoints( wallet: WalletViewModel , refreshIfNeeded: Bool ) async throws -> [ Endpoint ] {
230320 if refreshIfNeeded {
@@ -272,16 +362,6 @@ enum PublicPaykitService {
272362 return endpoints
273363 }
274364
275- private static func preferredPayableEndpoint( from endpoints: [ Endpoint ] ) async -> Endpoint ? {
276- for endpoint in endpoints {
277- if await isPayableEndpoint ( endpoint) {
278- return endpoint
279- }
280- }
281-
282- return nil
283- }
284-
285365 private static func isPayableEndpoint( _ endpoint: Endpoint ) async -> Bool {
286366 switch endpoint. methodId {
287367 case . bitcoinLightningBolt11:
0 commit comments