Skip to content
This repository has been archived by the owner on Nov 23, 2024. It is now read-only.

Commit

Permalink
Payments service implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
radmakr committed Nov 22, 2023
1 parent 55e1ded commit eaa89ae
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Sources/AlbyKit/AlbyKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ public final class AlbyKit {
// static var userAgent: String?

public let accountService = AccountsService()
public let invoicesService = InvoicesService()
public let paymentsService = PaymentsService()
}

23 changes: 23 additions & 0 deletions Sources/AlbyKit/Models/AlbyError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,26 @@ public struct ErrorMessage: Codable, Sendable {
public enum AlbyErrorCode: Int, Codable, Sendable {
case generic
}

/*
400: Bad Request
{
"code": 8,
"error": true,
"message": "string"
}
500: Internal Server Error
{
"code": 10,
"error": true,
"message": "error"
}

400: Bad Request
Invalid request body or Invoice could not be created
{
"code": 0,
"error": true,
"message": "string"
}
*/
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@ public struct InvoiceHistoryUploadModel: Codable, Sendable {

/// Items per page (Default 25)
public var items: Int?

public init(before: String? = nil, since: String? = nil, createdAtLt: Int? = nil, createdAtGt: Int? = nil, page: Int? = nil, items: Int? = nil) {
self.before = before
self.since = since
self.createdAtLt = createdAtLt
self.createdAtGt = createdAtGt
self.page = page
self.items = items
}
}
10 changes: 10 additions & 0 deletions Sources/AlbyKit/Models/PaymentsService/Bolt11Payment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

public struct Bolt11Payment: Codable, Sendable {
public let amount: Int
public let description: String
public let destination: String
public let fee: Int
public let paymentHash: String
public let paymentPreimage: String
public let paymentRequest: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

/// Object needed to pay a bolt11 invoice.
public struct Bolt11PaymentUploadModel: Codable, Sendable {

/// invoice to be paid
public var invoice: String

/// invoice amount (required if none in invoice itself). Must be a whole number greater than 0 (millisats not supported)
public var amount: Int64

public init(invoice: String, amount: Int64) {
self.invoice = invoice
self.amount = amount
}
}
26 changes: 26 additions & 0 deletions Sources/AlbyKit/Models/PaymentsService/KeysendPayment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

public struct KeysendPayment: Codable, Sendable {
public let amount: Int
public let description: String
public let descriptionHash: String
public let destination: String
public let fee: Int
public let customRecords: [String : String]?
public let paymentHash: String
public let paymentPreimage: String
}

public struct MultiKeysendPayment: Codable, Sendable {
public let error: KeysendPaymentError?
public let keysend: KeysendPayment
}

public struct KeysendPayments: Codable, Sendable {
public let keysends: [MultiKeysendPayment]
}

public struct KeysendPaymentError: Codable, Sendable {
public let code: Int
public let error: Bool
public let message: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

/// Keysend payment
/// Make a spontaneous keysend payment, with optional custom records. See for example: [https://github.com/lightning/blips/blob/master/blip-0010.md](https://github.com/lightning/blips/blob/master/blip-0010.md)
public struct KeysendPaymentUploadModel: Codable, Sendable {

/// Amount in satoshi. Must be a whole number greater than 0. (millisats are not supported)
public var amount: Int64

/// Destination hex-string pubkey (a string starting with 02 or 03)
public var destination: String

/// Internal memo
public var memo: String?

/// map with custom records. See [https://www.webln.guide/building-lightning-apps/webln-reference/webln.keysend](https://www.webln.guide/building-lightning-apps/webln-reference/webln.keysend)
public var customRecords: [String : String]?

public init(amount: Int64, destination: String, memo: String? = nil, customRecords: [String : String]? = nil) {
self.amount = amount
self.destination = destination
self.memo = memo
self.customRecords = customRecords
}
}

public struct MultiKeysendPaymentUploadModel: Codable, Sendable {

/// Array of keysend objects (`KeysendPaymentUploadModel`)
public var keysends: [KeysendPaymentUploadModel]

public init(keysends: [KeysendPaymentUploadModel]) {
self.keysends = keysends
}
}
71 changes: 71 additions & 0 deletions Sources/AlbyKit/Services/PaymentsService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Foundation

public struct PaymentsService {
private let router = NetworkRouter<PaymentsAPI>(decoder: .albyDecoder)

/// BOLT11 payment
/// Scope needed: payments:send
/// Pay a lightning invoice (bolt11)
/// - returns a `Bolt11Payment` object
public func bolt11Payment(uploadModel: Bolt11PaymentUploadModel) async throws -> Bolt11Payment {
try await router.execute(.bolt11(uploadModel))
}

/// Keysend payment
/// Scope needed: payments:send
/// Send a "spontaneous" payment (keysend). Used for push realtime/streaming push payments
/// - returns a `KeysendPayment` object
public func keysendPayment(uploadModel: KeysendPaymentUploadModel) async throws -> KeysendPayment {
try await router.execute(.keysend(uploadModel))
}

/// Multi keysend payment
/// Scope needed: `payments:send`
/// Send multiple spontaneous keysend payments. Useful for doing value4value splits. Request and response are an array of the single keysend payment request and response.
/// - returns a `KeysendPayments` object which is an array of `KeysendPayment` objects
public func multiKeysendPayment(uploadModel: MultiKeysendPaymentUploadModel) async throws -> KeysendPayments {
try await router.execute(.multiKeysend(uploadModel))
}
}

enum PaymentsAPI {
case bolt11(Bolt11PaymentUploadModel)
case keysend(KeysendPaymentUploadModel)
case multiKeysend(MultiKeysendPaymentUploadModel)
}

extension PaymentsAPI: EndpointType {
public var baseURL: URL {
guard let url = URL(string: prodAPI) else { fatalError("baseURL not configured.") }
return url
}

var path: String {
switch self {
case .bolt11: "/payments/bolt11"
case .keysend: "/payments/keysend"
case .multiKeysend: "/payments/keysend/multi"
}
}

var httpMethod: HTTPMethod {
switch self {
case .bolt11, .keysend, .multiKeysend: .post
}
}

var task: HTTPTask {
switch self {
case .bolt11(let uploadModel): return .requestParameters(encoding: .jsonEncodableEncoding(encodable: uploadModel))
case .keysend(let uploadModel): return .requestParameters(encoding: .jsonEncodableEncoding(encodable: uploadModel))
case .multiKeysend(let uploadModel): return .requestParameters(encoding: .jsonEncodableEncoding(encodable: uploadModel))
}
}

var headers: HTTPHeaders? {
nil
}
}



0 comments on commit eaa89ae

Please sign in to comment.