taler-ios

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

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