taler-ios

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

WalletBackendRequest.swift (8451B)


      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 {
     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 Merchant: Codable {
    110     var name: String
    111     var address: Location?
    112     var jurisdiction: Location?
    113 }
    114 
    115 /// A tax made on a payment.
    116 struct Tax: Codable {
    117     var name: String
    118     var tax: Amount
    119 }
    120 
    121 /// A product being purchased from a merchant.
    122 /// https://docs.taler.net/core/api-merchant.html#the-contract-terms
    123 struct Product: Codable, Identifiable {
    124     var product_id: String?
    125     var description: String
    126 //    var description_i18n:   ?
    127     var quantity: Int?
    128     var unit: String?
    129     var price: Amount?
    130     var image: String? // product image 128x128 encoded
    131     var taxes: [Tax]?
    132     var delivery_date: Timestamp?
    133 
    134     var id: String { product_id ?? "unknown" }
    135 }
    136 
    137 /// Brief information about an order.
    138 struct OrderShortInfo: Codable {
    139     var orderId: String
    140     var merchant: Merchant
    141     var summary: String
    142 //    var summary_i18n:   ?
    143     var products: [Product]?
    144     var fulfillmentUrl: String?
    145     var fulfillmentMessage: String?
    146 //    var fulfillmentMessage_i18n:    ?
    147     var contractTermsHash: String?
    148 }
    149 // MARK: -
    150 /// A request to process a refund.
    151 struct WalletBackendApplyRefundRequest: WalletBackendFormattedRequest {
    152     func operation() -> String { "applyRefund" }
    153     func args() -> Args { Args(talerRefundUri: talerRefundUri) }
    154 
    155     var talerRefundUri: String
    156 
    157     struct Args: Encodable {
    158         var talerRefundUri: String
    159     }
    160 
    161     struct Response: Decodable {
    162         var contractTermsHash: String
    163         var amountEffectivePaid: Amount
    164         var amountRefundGranted: Amount
    165         var amountRefundGone: Amount
    166         var pendingAtExchange: Bool
    167         var info: OrderShortInfo
    168     }
    169 }
    170 
    171 
    172 /// A request to force update an exchange.
    173 struct WalletBackendForceUpdateRequest: WalletBackendFormattedRequest {
    174     func operation() -> String { "addRequest" }
    175     func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl) }
    176 
    177     var exchangeBaseUrl: String
    178     struct Args: Encodable {
    179         var exchangeBaseUrl: String
    180     }
    181 
    182     struct Response: Decodable {}
    183 }
    184 
    185 /// A request to deposit funds.
    186 struct WalletBackendCreateDepositGroupRequest: WalletBackendFormattedRequest {
    187     func operation() -> String { "createDepositGroup" }
    188     func args() -> Args { Args(depositPayToUri: depositePayToUri, amount: amount) }
    189 
    190     var depositePayToUri: String
    191     var amount: Amount
    192     
    193     struct Args: Encodable {
    194         var depositPayToUri: String
    195         var amount: Amount
    196     }
    197     
    198     struct Response: Decodable {
    199         var depositGroupId: String
    200     }
    201 }
    202 
    203 /// A request to get information about a payment request.
    204 struct WalletBackendPreparePayRequest: WalletBackendFormattedRequest {
    205     func operation() -> String { "preparePay" }
    206     func args() -> Args { Args(talerPayUri: talerPayUri) }
    207     var talerPayUri: String
    208 
    209     struct Args: Encodable {
    210         var talerPayUri: String
    211     }
    212 
    213     struct Response: Decodable {}
    214 }
    215 
    216 // MARK: -
    217 struct IntegrationTestArgs: Codable {
    218     var exchangeBaseUrl: String
    219     var bankBaseUrl: String
    220     var merchantBaseUrl: String
    221     var merchantApiKey: String
    222     var amountToWithdraw: String
    223     var amountToSpend: String
    224 }
    225 
    226 /// A request to run a basic integration test.
    227 struct WalletBackendRunIntegrationTestRequest: WalletBackendFormattedRequest {
    228     func operation() -> String { "runIntegrationTest" }
    229     func args() -> Args { integrationTestArgs }
    230     var integrationTestArgs: IntegrationTestArgs
    231     
    232     typealias Args = IntegrationTestArgs
    233     
    234     struct Response: Decodable {}
    235 }
    236 
    237 struct TestPayArgs: Codable {
    238     var merchantBaseUrl: String
    239     var merchantApiKey: String
    240     var amount: String
    241     var summary: String
    242 }
    243 
    244 /// A request to make a test payment.
    245 struct WalletBackendTestPayRequest: WalletBackendFormattedRequest {
    246     func operation() -> String { "testPay" }
    247     func args() -> Args { testPayArgs }
    248 
    249     var testPayArgs: TestPayArgs
    250     typealias Args = TestPayArgs
    251     
    252     struct Response: Decodable {}
    253 }
    254 
    255 struct Coin: Codable {
    256     var denom_pub: String
    257     var denom_pub_hash: String
    258     var denom_value: String
    259     var coin_pub: String
    260     var exchange_base_url: String
    261     var remaining_value: String
    262     var refresh_parent_coin_pub: String
    263     var withdrawal_reserve_pub: String
    264     var coin_suspended: Bool
    265 }
    266 
    267 /// A request to dump all coins to JSON.
    268 struct WalletBackendDumpCoinsRequest: WalletBackendFormattedRequest {
    269     func operation() -> String { "dumpCoins" }
    270     func args() -> Args { Args() }
    271     struct Args: Encodable { }
    272 
    273     struct Response: Decodable {
    274         var coins: [Coin]
    275     }
    276     
    277 }
    278 
    279 /// A request to suspend or unsuspend a coin.
    280 struct WalletBackendSuspendCoinRequest: WalletBackendFormattedRequest {
    281     struct Response: Decodable {}
    282     func operation() -> String { "setCoinSuspended" }
    283     func args() -> Args { Args(coinPub: coinPub, suspended: suspended) }
    284 
    285     var coinPub: String
    286     var suspended: Bool
    287     
    288     struct Args: Encodable {
    289         var coinPub: String
    290         var suspended: Bool
    291     }
    292 }
    293 
    294