taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

Model+P2P.swift (11288B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-26 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * @author Marc Stibane
      7  */
      8 import Foundation
      9 import taler_swift
     10 import AnyCodable
     11 //import SymLog
     12 
     13 // MARK: common structures
     14 struct PeerContractTerms: Codable {
     15     let amount: Amount
     16     let summary: String
     17     // Optional only for InitiatePeerPushDebit:
     18     // if nil then defaultExpiration is taken
     19     let purse_expiration: Timestamp?
     20     let icon_id: String?
     21 }
     22 // MARK: - max PeerPushDebit amount
     23 /// Check if initiating a peer push payment is possible, check fees
     24 fileprivate struct AmountResponse: Codable {
     25     let effectiveAmount: Amount?
     26     let rawAmount: Amount
     27 }
     28 fileprivate struct GetMaxPeerPushDebitAmount: WalletBackendFormattedRequest {
     29     typealias Response = AmountResponse
     30     var operation: String { "getMaxPeerPushDebitAmount" }
     31     func args() -> Args { Args(currency: scope.currency,
     32                           restrictScope: scope) }
     33     var scope: ScopeInfo
     34     struct Args: Encodable {
     35         var currency: String
     36         var restrictScope: ScopeInfo
     37     }
     38 }
     39 extension WalletModel {
     40     nonisolated func getMaxPeerPushDebitAmount(_ scope: ScopeInfo,
     41                                            viewHandles: Bool = false)
     42       async throws -> Amount {
     43         let request = GetMaxPeerPushDebitAmount(scope: scope)
     44         let response = try await sendRequest(request, viewHandles: viewHandles)
     45         return response.rawAmount
     46     }
     47 } // getMaxPeerPushAmount
     48 // MARK: - check PeerPushDebit
     49 struct CheckPeerPushDebitResponse: Codable {
     50     let exchangeBaseUrl: String?                // API "2:0:1"
     51     let amountRaw: Amount
     52     let amountEffective: Amount
     53     let defaultExpiration: Duration
     54     let maxExpirationDate: Timestamp?           // API "2:0:1" TODO: limit expiration (30 days or 7 days)
     55 }
     56 fileprivate struct CheckPeerPushDebit: WalletBackendFormattedRequest {
     57     typealias Response = CheckPeerPushDebitResponse
     58     var operation: String { "checkPeerPushDebit" }
     59     func args() -> Args { Args(amount: amount,
     60                         restrictScope: scope,
     61                         progressToken: operation) }
     62     var amount: Amount
     63     var scope: ScopeInfo
     64     struct Args: Encodable {
     65         var amount: Amount
     66         var restrictScope: ScopeInfo
     67         var progressToken: String?
     68     }
     69 }
     70 extension WalletModel {
     71     nonisolated func checkPeerPushDebit(_ amount: Amount,
     72                                            scope: ScopeInfo,
     73                                      viewHandles: Bool = false)
     74       async throws -> CheckPeerPushDebitResponse {
     75         let request = CheckPeerPushDebit(amount: amount, scope: scope)
     76 //        let controller = Controller.shared
     77 //        controller.progressOperation = request.operation
     78 //        controller.progressToken = request.operation
     79         let response = try await sendRequest(request, viewHandles: viewHandles)
     80         return response
     81     }
     82 } // checkPeerPushDebit
     83 // MARK: - Initiate PeerPushDebit
     84 /// Initiate an outgoing peer push payment, send coins
     85 struct InitiatePeerPushDebitResponse: Codable {
     86     let contractPriv: String
     87     let mergePriv: String
     88     let pursePub: String
     89     let exchangeBaseUrl: String
     90 //    let talerUri: String?
     91     let transactionId: String
     92 }
     93 fileprivate struct InitiatePeerPushDebit: WalletBackendFormattedRequest {
     94     typealias Response = InitiatePeerPushDebitResponse
     95     var operation: String { "initiatePeerPushDebit" }
     96     func args() -> Args { Args(restrictScope: scope,
     97                         partialContractTerms: terms) }
     98     var scope: ScopeInfo
     99     var terms: PeerContractTerms
    100     struct Args: Encodable {
    101         var restrictScope: ScopeInfo
    102         var partialContractTerms: PeerContractTerms
    103     }
    104 }
    105 extension WalletModel {
    106     nonisolated func initiatePeerPushDebit(scope: ScopeInfo,
    107                                            terms: PeerContractTerms,
    108                                      viewHandles: Bool = false)
    109       async throws -> InitiatePeerPushDebitResponse {
    110         let request = InitiatePeerPushDebit(scope: scope, terms: terms)
    111         let response = try await sendRequest(request, viewHandles: viewHandles)
    112         return response
    113     }
    114 } // initiatePeerPushDebit
    115 // MARK: - PeerPullCredit
    116 /// Check fees before sending a request(invoice) to another wallet
    117 struct CheckPeerPullCreditResponse: Codable {
    118     let scopeInfo: ScopeInfo?
    119     let exchangeBaseUrl: String?
    120     let amountRaw: Amount
    121     let amountEffective: Amount
    122     var numCoins: Int?                  // Number of coins this amountEffective will create
    123 }
    124 fileprivate struct CheckPeerPullCredit: WalletBackendFormattedRequest {
    125     typealias Response = CheckPeerPullCreditResponse
    126     var operation: String { "checkPeerPullCredit" }
    127     func args() -> Args { Args(amount: amount,
    128                         restrictScope: scope,
    129                       exchangeBaseUrl: scope?.url,
    130                         progressToken: operation) }
    131     var amount: Amount
    132     var scope: ScopeInfo?
    133     struct Args: Encodable {
    134         var amount: Amount
    135         var restrictScope: ScopeInfo?
    136         var exchangeBaseUrl: String?
    137         var progressToken: String?
    138     }
    139 }
    140 extension WalletModel {
    141     nonisolated func checkPeerPullCredit(_ amount: Amount,
    142                                             scope: ScopeInfo,
    143                                       viewHandles: Bool = false)
    144       async throws -> CheckPeerPullCreditResponse {
    145         let request = CheckPeerPullCredit(amount: amount, scope: scope)
    146         let controller = Controller.shared
    147         controller.progressOperation = request.operation
    148         controller.progressToken = request.operation
    149         let response = try await sendRequest(request, viewHandles: viewHandles)
    150         return response
    151     }
    152 } // checkPeerPullCredit
    153 // - - - - - -
    154 /// Initiate an outgoing peer pull payment, send a request(invoice)
    155 struct InitiatePeerPullCreditResponse: Codable {
    156     let talerUri: String
    157     let transactionId: String
    158 }
    159 fileprivate struct InitiatePeerPullCredit: WalletBackendFormattedRequest {
    160     typealias Response = InitiatePeerPullCreditResponse
    161     var operation: String { "initiatePeerPullCredit" }
    162     func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl,
    163                           partialContractTerms: partialContractTerms) }
    164     var exchangeBaseUrl: String?
    165     var partialContractTerms: PeerContractTerms
    166     struct Args: Encodable {
    167         var exchangeBaseUrl: String?
    168         var partialContractTerms: PeerContractTerms
    169     }
    170 }
    171 extension WalletModel {
    172     nonisolated func initiatePeerPullCredit(_ baseURL: String?,
    173                                                 terms: PeerContractTerms,
    174                                           viewHandles: Bool = false)
    175       async throws -> InitiatePeerPullCreditResponse {
    176         let request = InitiatePeerPullCredit(exchangeBaseUrl: baseURL,
    177                                         partialContractTerms: terms)
    178         let response = try await sendRequest(request, viewHandles: viewHandles)
    179         return response
    180     }
    181 } // initiatePeerPullCredit
    182 // MARK: - PeerPushCredit
    183 /// Prepare an incoming peer push payment, receive coins
    184 struct PreparePeerPushCreditResponse: Codable {
    185     let contractTerms: PeerContractTerms
    186     let amountRaw: Amount
    187     let amountEffective: Amount
    188     // TODO: the dialog transaction is already created in the local DB - must either accept or delete
    189     let transactionId: String
    190     let txState: TransactionState
    191     let exchangeBaseUrl: String         // need (exchange.tosStatus == .accepted) for incoming coins
    192     let scopeInfo: ScopeInfo
    193 }
    194 fileprivate struct PreparePeerPushCredit: WalletBackendFormattedRequest {
    195     typealias Response = PreparePeerPushCreditResponse
    196     var operation: String { "preparePeerPushCredit" }
    197     func args() -> Args { Args(talerUri: talerUri) }
    198 
    199     var talerUri: String
    200     struct Args: Encodable {
    201         var talerUri: String
    202     }
    203 }
    204 extension WalletModel {
    205     nonisolated func preparePeerPushCredit(_ talerUri: String,
    206                                           viewHandles: Bool = false)
    207       async throws -> PreparePeerPushCreditResponse {
    208         let request = PreparePeerPushCredit(talerUri: talerUri)
    209         let response = try await sendRequest(request, viewHandles: viewHandles)
    210         return response
    211     }
    212 } // preparePeerPushCredit
    213 // - - - - - -
    214 /// Accept an incoming peer push payment
    215 fileprivate struct AcceptPeerPushCredit: WalletBackendFormattedRequest {
    216     struct Response: Decodable {}   // no result - getting no error back means success
    217     var operation: String { "confirmPeerPushCredit" } // should be "acceptPeerPushCredit"
    218     func args() -> Args { Args(transactionId: transactionId) }
    219 
    220     var transactionId: String
    221     struct Args: Encodable {
    222         var transactionId: String
    223     }
    224 }
    225 extension WalletModel {
    226     nonisolated func acceptPeerPushCredit(_ transactionId: String,
    227                                               viewHandles: Bool = false)
    228       async throws -> Decodable {
    229         let request = AcceptPeerPushCredit(transactionId: transactionId)
    230         let response = try await sendRequest(request, viewHandles: viewHandles)
    231         return response
    232     }
    233 } // acceptPeerPushCredit
    234 // MARK: - PeerPullDebit
    235 /// Prepare an incoming peer push request(invoice), pay coins
    236 struct PreparePeerPullDebitResponse: Codable {
    237     let contractTerms: PeerContractTerms
    238     let amountRaw: Amount
    239     let amountEffective: Amount
    240     // TODO: the dialog transaction is already created in the local DB - must either accept or delete
    241     let transactionId: String
    242     let txState: TransactionState
    243 //    let exchangeBaseUrl: String       use scope instead
    244     let scopeInfo: ScopeInfo
    245 }
    246 fileprivate struct PreparePeerPullDebit: WalletBackendFormattedRequest {
    247     typealias Response = PreparePeerPullDebitResponse
    248     var operation: String { "preparePeerPullDebit" }
    249     func args() -> Args { Args(talerUri: talerUri) }
    250 
    251     var talerUri: String
    252     struct Args: Encodable {
    253         var talerUri: String
    254     }
    255 }
    256 extension WalletModel {
    257     nonisolated func preparePeerPullDebit(_ talerUri: String,
    258                                          viewHandles: Bool = false)
    259       async throws -> PreparePeerPullDebitResponse {
    260         let request = PreparePeerPullDebit(talerUri: talerUri)
    261         let response = try await sendRequest(request, viewHandles: viewHandles)
    262         return response
    263     }
    264 } // preparePeerPullDebit
    265 // - - - - - -
    266 /// Confirm incoming peer push request(invoice) and pay
    267 fileprivate struct ConfirmPeerPullDebit: WalletBackendFormattedRequest {
    268     struct Response: Decodable {}   // no result - getting no error back means success
    269     var operation: String { "confirmPeerPullDebit" }
    270     func args() -> Args { Args(transactionId: transactionId) }
    271 
    272     var transactionId: String
    273     struct Args: Encodable {
    274         var transactionId: String
    275     }
    276 }
    277 extension WalletModel {
    278     nonisolated func confirmPeerPullDebit(_ transactionId: String,
    279                                               viewHandles: Bool = false)
    280       async throws -> Decodable {
    281         let request = ConfirmPeerPullDebit(transactionId: transactionId)
    282         let response = try await sendRequest(request, viewHandles: viewHandles)
    283         return response
    284     }
    285 } // confirmPeerPullDebit