Model+P2P.swift (11031B)
1 /* 2 * This file is part of GNU Taler, ©2022-25 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 func 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 func operation() -> String { "checkPeerPushDebit" } 59 func args() -> Args { Args(amount: amount, 60 restrictScope: scope, 61 clientCancellationId: "cancel") } 62 var amount: Amount 63 var scope: ScopeInfo 64 struct Args: Encodable { 65 var amount: Amount 66 var restrictScope: ScopeInfo 67 var clientCancellationId: 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 response = try await sendRequest(request, viewHandles: viewHandles) 77 return response 78 } 79 } // checkPeerPushDebit 80 // MARK: - Initiate PeerPushDebit 81 /// Initiate an outgoing peer push payment, send coins 82 struct InitiatePeerPushDebitResponse: Codable { 83 let contractPriv: String 84 let mergePriv: String 85 let pursePub: String 86 let exchangeBaseUrl: String 87 let talerUri: String? 88 let transactionId: String 89 } 90 fileprivate struct InitiatePeerPushDebit: WalletBackendFormattedRequest { 91 typealias Response = InitiatePeerPushDebitResponse 92 func operation() -> String { "initiatePeerPushDebit" } 93 func args() -> Args { Args(restrictScope: scope, 94 partialContractTerms: terms) } 95 var scope: ScopeInfo 96 var terms: PeerContractTerms 97 struct Args: Encodable { 98 var restrictScope: ScopeInfo 99 var partialContractTerms: PeerContractTerms 100 } 101 } 102 extension WalletModel { 103 nonisolated func initiatePeerPushDebit(scope: ScopeInfo, 104 terms: PeerContractTerms, 105 viewHandles: Bool = false) 106 async throws -> InitiatePeerPushDebitResponse { 107 let request = InitiatePeerPushDebit(scope: scope, terms: terms) 108 let response = try await sendRequest(request, viewHandles: viewHandles) 109 return response 110 } 111 } // initiatePeerPushDebit 112 // MARK: - PeerPullCredit 113 /// Check fees before sending a request(invoice) to another wallet 114 struct CheckPeerPullCreditResponse: Codable { 115 let scopeInfo: ScopeInfo? 116 let exchangeBaseUrl: String? 117 let amountRaw: Amount 118 let amountEffective: Amount 119 var numCoins: Int? // Number of coins this amountEffective will create 120 } 121 fileprivate struct CheckPeerPullCredit: WalletBackendFormattedRequest { 122 typealias Response = CheckPeerPullCreditResponse 123 func operation() -> String { "checkPeerPullCredit" } 124 func args() -> Args { Args(amount: amount, 125 restrictScope: scope, 126 exchangeBaseUrl: scope?.url, 127 clientCancellationId: "cancel") } 128 var amount: Amount 129 var scope: ScopeInfo? 130 struct Args: Encodable { 131 var amount: Amount 132 var restrictScope: ScopeInfo? 133 var exchangeBaseUrl: String? 134 var clientCancellationId: String? 135 } 136 } 137 extension WalletModel { 138 nonisolated func checkPeerPullCredit(_ amount: Amount, 139 scope: ScopeInfo, 140 viewHandles: Bool = false) 141 async throws -> CheckPeerPullCreditResponse { 142 let request = CheckPeerPullCredit(amount: amount, scope: scope) 143 let response = try await sendRequest(request, viewHandles: viewHandles) 144 return response 145 } 146 } // checkPeerPullCredit 147 // - - - - - - 148 /// Initiate an outgoing peer pull payment, send a request(invoice) 149 struct InitiatePeerPullCreditResponse: Codable { 150 let talerUri: String 151 let transactionId: String 152 } 153 fileprivate struct InitiatePeerPullCredit: WalletBackendFormattedRequest { 154 typealias Response = InitiatePeerPullCreditResponse 155 func operation() -> String { "initiatePeerPullCredit" } 156 func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl, 157 partialContractTerms: partialContractTerms) } 158 var exchangeBaseUrl: String? 159 var partialContractTerms: PeerContractTerms 160 struct Args: Encodable { 161 var exchangeBaseUrl: String? 162 var partialContractTerms: PeerContractTerms 163 } 164 } 165 extension WalletModel { 166 nonisolated func initiatePeerPullCredit(_ baseURL: String?, 167 terms: PeerContractTerms, 168 viewHandles: Bool = false) 169 async throws -> InitiatePeerPullCreditResponse { 170 let request = InitiatePeerPullCredit(exchangeBaseUrl: baseURL, 171 partialContractTerms: terms) 172 let response = try await sendRequest(request, viewHandles: viewHandles) 173 return response 174 } 175 } // initiatePeerPullCredit 176 // MARK: - PeerPushCredit 177 /// Prepare an incoming peer push payment, receive coins 178 struct PreparePeerPushCreditResponse: Codable { 179 let contractTerms: PeerContractTerms 180 let amountRaw: Amount 181 let amountEffective: Amount 182 // TODO: the dialog transaction is already created in the local DB - must either accept or delete 183 let transactionId: String 184 let txState: TransactionState 185 let exchangeBaseUrl: String // need (exchange.tosStatus == .accepted) for incoming coins 186 let scopeInfo: ScopeInfo 187 } 188 fileprivate struct PreparePeerPushCredit: WalletBackendFormattedRequest { 189 typealias Response = PreparePeerPushCreditResponse 190 func operation() -> String { "preparePeerPushCredit" } 191 func args() -> Args { Args(talerUri: talerUri) } 192 193 var talerUri: String 194 struct Args: Encodable { 195 var talerUri: String 196 } 197 } 198 extension WalletModel { 199 nonisolated func preparePeerPushCredit(_ talerUri: String, 200 viewHandles: Bool = false) 201 async throws -> PreparePeerPushCreditResponse { 202 let request = PreparePeerPushCredit(talerUri: talerUri) 203 let response = try await sendRequest(request, viewHandles: viewHandles) 204 return response 205 } 206 } // preparePeerPushCredit 207 // - - - - - - 208 /// Accept an incoming peer push payment 209 fileprivate struct AcceptPeerPushCredit: WalletBackendFormattedRequest { 210 struct Response: Decodable {} // no result - getting no error back means success 211 func operation() -> String { "confirmPeerPushCredit" } // should be "acceptPeerPushCredit" 212 func args() -> Args { Args(transactionId: transactionId) } 213 214 var transactionId: String 215 struct Args: Encodable { 216 var transactionId: String 217 } 218 } 219 extension WalletModel { 220 nonisolated func acceptPeerPushCredit(_ transactionId: String, 221 viewHandles: Bool = false) 222 async throws -> Decodable { 223 let request = AcceptPeerPushCredit(transactionId: transactionId) 224 let response = try await sendRequest(request, viewHandles: viewHandles) 225 return response 226 } 227 } // acceptPeerPushCredit 228 // MARK: - PeerPullDebit 229 /// Prepare an incoming peer push request(invoice), pay coins 230 struct PreparePeerPullDebitResponse: Codable { 231 let contractTerms: PeerContractTerms 232 let amountRaw: Amount 233 let amountEffective: Amount 234 // TODO: the dialog transaction is already created in the local DB - must either accept or delete 235 let transactionId: String 236 let txState: TransactionState 237 // let exchangeBaseUrl: String use scope instead 238 let scopeInfo: ScopeInfo 239 } 240 fileprivate struct PreparePeerPullDebit: WalletBackendFormattedRequest { 241 typealias Response = PreparePeerPullDebitResponse 242 func operation() -> String { "preparePeerPullDebit" } 243 func args() -> Args { Args(talerUri: talerUri) } 244 245 var talerUri: String 246 struct Args: Encodable { 247 var talerUri: String 248 } 249 } 250 extension WalletModel { 251 nonisolated func preparePeerPullDebit(_ talerUri: String, 252 viewHandles: Bool = false) 253 async throws -> PreparePeerPullDebitResponse { 254 let request = PreparePeerPullDebit(talerUri: talerUri) 255 let response = try await sendRequest(request, viewHandles: viewHandles) 256 return response 257 } 258 } // preparePeerPullDebit 259 // - - - - - - 260 /// Confirm incoming peer push request(invoice) and pay 261 fileprivate struct ConfirmPeerPullDebit: WalletBackendFormattedRequest { 262 struct Response: Decodable {} // no result - getting no error back means success 263 func operation() -> String { "confirmPeerPullDebit" } 264 func args() -> Args { Args(transactionId: transactionId) } 265 266 var transactionId: String 267 struct Args: Encodable { 268 var transactionId: String 269 } 270 } 271 extension WalletModel { 272 nonisolated func confirmPeerPullDebit(_ transactionId: String, 273 viewHandles: Bool = false) 274 async throws -> Decodable { 275 let request = ConfirmPeerPullDebit(transactionId: transactionId) 276 let response = try await sendRequest(request, viewHandles: viewHandles) 277 return response 278 } 279 } // confirmPeerPullDebit