taler-ios

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

WalletBackendRequest.swift (8094B)


      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 force update an exchange.
    158 struct WalletBackendForceUpdateRequest: WalletBackendFormattedRequest {
    159     func operation() -> String { "addRequest" }
    160     func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl) }
    161 
    162     var exchangeBaseUrl: String
    163     struct Args: Encodable {
    164         var exchangeBaseUrl: String
    165     }
    166 
    167     struct Response: Decodable {}
    168 }
    169 
    170 /// A request to deposit funds.
    171 struct WalletBackendCreateDepositGroupRequest: WalletBackendFormattedRequest {
    172     func operation() -> String { "createDepositGroup" }
    173     func args() -> Args { Args(depositPayToUri: depositePayToUri, amount: amount) }
    174 
    175     var depositePayToUri: String
    176     var amount: Amount
    177     
    178     struct Args: Encodable {
    179         var depositPayToUri: String
    180         var amount: Amount
    181     }
    182     
    183     struct Response: Decodable {
    184         var depositGroupId: String
    185     }
    186 }
    187 
    188 /// A request to get information about a payment request.
    189 struct WalletBackendPreparePayRequest: WalletBackendFormattedRequest {
    190     func operation() -> String { "preparePay" }
    191     func args() -> Args { Args(talerPayUri: talerPayUri) }
    192     var talerPayUri: String
    193 
    194     struct Args: Encodable {
    195         var talerPayUri: String
    196     }
    197 
    198     struct Response: Decodable {}
    199 }
    200 
    201 // MARK: -
    202 struct IntegrationTestArgs: Codable {
    203     var exchangeBaseUrl: String
    204     var bankBaseUrl: String
    205     var merchantBaseUrl: String
    206     var merchantApiKey: String
    207     var amountToWithdraw: String
    208     var amountToSpend: String
    209 }
    210 
    211 /// A request to run a basic integration test.
    212 struct WalletBackendRunIntegrationTestRequest: WalletBackendFormattedRequest {
    213     func operation() -> String { "runIntegrationTest" }
    214     func args() -> Args { integrationTestArgs }
    215     var integrationTestArgs: IntegrationTestArgs
    216     
    217     typealias Args = IntegrationTestArgs
    218     
    219     struct Response: Decodable {}
    220 }
    221 
    222 struct TestPayArgs: Codable {
    223     var merchantBaseUrl: String
    224     var merchantApiKey: String
    225     var amount: String
    226     var summary: String
    227 }
    228 
    229 /// A request to make a test payment.
    230 struct WalletBackendTestPayRequest: WalletBackendFormattedRequest {
    231     func operation() -> String { "testPay" }
    232     func args() -> Args { testPayArgs }
    233 
    234     var testPayArgs: TestPayArgs
    235     typealias Args = TestPayArgs
    236     
    237     struct Response: Decodable {}
    238 }
    239 
    240 struct Coin: Codable {
    241     var denom_pub: String
    242     var denom_pub_hash: String
    243     var denom_value: String
    244     var coin_pub: String
    245     var exchange_base_url: String
    246     var remaining_value: String
    247     var refresh_parent_coin_pub: String
    248     var withdrawal_reserve_pub: String
    249     var coin_suspended: Bool
    250 }
    251 
    252 /// A request to dump all coins to JSON.
    253 struct WalletBackendDumpCoinsRequest: WalletBackendFormattedRequest {
    254     func operation() -> String { "dumpCoins" }
    255     func args() -> Args { Args() }
    256     struct Args: Encodable { }
    257 
    258     struct Response: Decodable {
    259         var coins: [Coin]
    260     }
    261     
    262 }
    263 
    264 /// A request to suspend or unsuspend a coin.
    265 struct WalletBackendSuspendCoinRequest: WalletBackendFormattedRequest {
    266     struct Response: Decodable {}
    267     func operation() -> String { "setCoinSuspended" }
    268     func args() -> Args { Args(coinPub: coinPub, suspended: suspended) }
    269 
    270     var coinPub: String
    271     var suspended: Bool
    272     
    273     struct Args: Encodable {
    274         var coinPub: String
    275         var suspended: Bool
    276     }
    277 }
    278 
    279