WalletBackendRequest.swift (8686B)
1 /* 2 * This file is part of GNU Taler, ©2022-25 Taler Systems S.A. 3 * See LICENSE.md 4 */ 5 /** 6 * @author Jonathan Buchanan 7 * @author Marc Stibane 8 */ 9 import Foundation 10 import AnyCodable 11 import taler_swift 12 13 /// A request sent to the wallet backend. 14 struct WalletBackendRequest: Encodable { 15 /// The operation name of the request. 16 var operation: String 17 18 /// The body of the request as JSON. 19 var args: AnyEncodable 20 } 21 22 protocol WalletBackendFormattedRequest { 23 associatedtype Args: Encodable 24 associatedtype Response: Decodable 25 26 func operation() -> String 27 func args() -> Args 28 } 29 // MARK: - 30 /// The scope of a currency: either global or a dedicated exchange 31 struct ScopeInfo: Codable, Hashable { 32 enum ScopeInfoType: String, Codable { 33 case global 34 case exchange 35 case auditor 36 case madeUp // => type unknown, currency name taken from amount 37 } 38 var type: ScopeInfoType 39 var currency: String // 3-char ISO 4217 code for global currency. Regional MUST be >= 4 letters 40 var noFees: Bool? // only for "global". Regional have this field per Exchange 41 var url: String? // only for "exchange" and "auditor" 42 43 public static func zero() -> ScopeInfo { 44 ScopeInfo(type: .madeUp, currency: UNKNOWN) 45 } 46 public static func zero(_ currency: String) -> ScopeInfo { 47 ScopeInfo(type: .madeUp, currency: currency) 48 } 49 public static func < (lhs: ScopeInfo, rhs: ScopeInfo) -> Bool { 50 if lhs.type == .global { 51 if rhs.type == .global { // both global ==> alphabetic currency 52 return lhs.currency < rhs.currency 53 } 54 return true // global comes first 55 } 56 if rhs.type == .global { 57 return false // global comes first 58 } 59 if lhs.currency == rhs.currency { 60 if let lhsBaseURL = lhs.url { 61 if let rhsBaseURL = rhs.url { 62 return lhsBaseURL < rhsBaseURL 63 } 64 return true 65 } 66 if rhs.url != nil { 67 return false 68 } 69 // fall thru 70 } 71 return lhs.currency < rhs.currency 72 } 73 public static func == (lhs: ScopeInfo, rhs: ScopeInfo) -> Bool { 74 if let lhsBaseURL = lhs.url { 75 if let rhsBaseURL = rhs.url { 76 if lhsBaseURL != rhsBaseURL { return false } // different exchanges 77 // else fall thru and check type & currency 78 } else { return false } // left but not right 79 } else if rhs.url != nil { 80 return false // right but not left 81 } 82 return lhs.type == rhs.type && 83 lhs.currency == rhs.currency 84 } 85 public func hash(into hasher: inout Hasher) { 86 hasher.combine(type) 87 if let url { 88 hasher.combine(url) 89 } 90 hasher.combine(currency) 91 } 92 } 93 // MARK: - 94 /// A billing or mailing location. 95 struct Location: Codable, Equatable, Hashable { 96 var country: String? 97 var country_subdivision: String? 98 var district: String? 99 var town: String? 100 var town_location: String? 101 var post_code: String? 102 var street: String? 103 var building_name: String? 104 var building_number: String? 105 var address_lines: [String]? 106 } 107 108 /// Information identifying a merchant. 109 struct MerchantInfo: Identifiable, Codable, Hashable, Sendable { 110 var name: String 111 var email: String? 112 var website: String? 113 var logo: String? // ImageDataUrl 114 var address: Location? 115 var jurisdiction: Location? 116 117 var id: String { 118 return name + (email ?? EMPTYSTRING) 119 } 120 } 121 122 /// A tax made on a payment. 123 struct Tax: Codable { 124 var name: String 125 var tax: Amount 126 } 127 128 /// A product being purchased from a merchant. 129 /// https://docs.taler.net/core/api-merchant.html#the-contract-terms 130 struct Product: Codable, Identifiable { 131 var product_id: String? 132 var description: String 133 // var description_i18n: ? 134 var quantity: Int? 135 var unit: String? 136 var price: Amount? 137 var image: String? // product image 128x128 encoded 138 var taxes: [Tax]? 139 var delivery_date: Timestamp? 140 141 var id: String { product_id ?? "unknown" } 142 } 143 144 /// Brief information about an order. 145 struct OrderShortInfo: Codable { 146 var orderId: String 147 var merchant: MerchantInfo 148 var summary: String 149 var summary_i18n: I18nDict? 150 var products: [Product]? 151 var fulfillmentUrl: String? 152 var fulfillmentMessage: String? 153 var fulfillmentMessage_i18n: I18nDict? 154 var contractTermsHash: String? 155 } 156 // MARK: - 157 /// A request to process a refund. 158 struct WalletBackendApplyRefundRequest: WalletBackendFormattedRequest { 159 func operation() -> String { "applyRefund" } 160 func args() -> Args { Args(talerRefundUri: talerRefundUri) } 161 162 var talerRefundUri: String 163 164 struct Args: Encodable { 165 var talerRefundUri: String 166 } 167 168 struct Response: Decodable { 169 var contractTermsHash: String 170 var amountEffectivePaid: Amount 171 var amountRefundGranted: Amount 172 var amountRefundGone: Amount 173 var pendingAtExchange: Bool 174 var info: OrderShortInfo 175 } 176 } 177 178 179 /// A request to force update an exchange. 180 struct WalletBackendForceUpdateRequest: WalletBackendFormattedRequest { 181 func operation() -> String { "addRequest" } 182 func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl) } 183 184 var exchangeBaseUrl: String 185 struct Args: Encodable { 186 var exchangeBaseUrl: String 187 } 188 189 struct Response: Decodable {} 190 } 191 192 /// A request to deposit funds. 193 struct WalletBackendCreateDepositGroupRequest: WalletBackendFormattedRequest { 194 func operation() -> String { "createDepositGroup" } 195 func args() -> Args { Args(depositPayToUri: depositePayToUri, amount: amount) } 196 197 var depositePayToUri: String 198 var amount: Amount 199 200 struct Args: Encodable { 201 var depositPayToUri: String 202 var amount: Amount 203 } 204 205 struct Response: Decodable { 206 var depositGroupId: String 207 } 208 } 209 210 /// A request to get information about a payment request. 211 struct WalletBackendPreparePayRequest: WalletBackendFormattedRequest { 212 func operation() -> String { "preparePay" } 213 func args() -> Args { Args(talerPayUri: talerPayUri) } 214 var talerPayUri: String 215 216 struct Args: Encodable { 217 var talerPayUri: String 218 } 219 220 struct Response: Decodable {} 221 } 222 223 // MARK: - 224 struct IntegrationTestArgs: Codable { 225 var exchangeBaseUrl: String 226 var bankBaseUrl: String 227 var merchantBaseUrl: String 228 var merchantApiKey: String 229 var amountToWithdraw: String 230 var amountToSpend: String 231 } 232 233 /// A request to run a basic integration test. 234 struct WalletBackendRunIntegrationTestRequest: WalletBackendFormattedRequest { 235 func operation() -> String { "runIntegrationTest" } 236 func args() -> Args { integrationTestArgs } 237 var integrationTestArgs: IntegrationTestArgs 238 239 typealias Args = IntegrationTestArgs 240 241 struct Response: Decodable {} 242 } 243 244 struct TestPayArgs: Codable { 245 var merchantBaseUrl: String 246 var merchantApiKey: String 247 var amount: String 248 var summary: String 249 } 250 251 /// A request to make a test payment. 252 struct WalletBackendTestPayRequest: WalletBackendFormattedRequest { 253 func operation() -> String { "testPay" } 254 func args() -> Args { testPayArgs } 255 256 var testPayArgs: TestPayArgs 257 typealias Args = TestPayArgs 258 259 struct Response: Decodable {} 260 } 261 262 struct Coin: Codable { 263 var denom_pub: String 264 var denom_pub_hash: String 265 var denom_value: String 266 var coin_pub: String 267 var exchange_base_url: String 268 var remaining_value: String 269 var refresh_parent_coin_pub: String 270 var withdrawal_reserve_pub: String 271 var coin_suspended: Bool 272 } 273 274 /// A request to dump all coins to JSON. 275 struct WalletBackendDumpCoinsRequest: WalletBackendFormattedRequest { 276 func operation() -> String { "dumpCoins" } 277 func args() -> Args { Args() } 278 struct Args: Encodable { } 279 280 struct Response: Decodable { 281 var coins: [Coin] 282 } 283 284 } 285 286 /// A request to suspend or unsuspend a coin. 287 struct WalletBackendSuspendCoinRequest: WalletBackendFormattedRequest { 288 struct Response: Decodable {} 289 func operation() -> String { "setCoinSuspended" } 290 func args() -> Args { Args(coinPub: coinPub, suspended: suspended) } 291 292 var coinPub: String 293 var suspended: Bool 294 295 struct Args: Encodable { 296 var coinPub: String 297 var suspended: Bool 298 } 299 } 300 301