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