summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2021-09-06 00:50:22 -0400
committerJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2021-09-06 00:50:22 -0400
commitc6998563642e8574bc57385371008e7a8579c8e8 (patch)
treec11069fb443bd428cd1fa0404637796138a68ccf
parentc98d8fbcbdb1767d9ae2caae3d58d97f06d278d1 (diff)
downloadtaler-ios-c6998563642e8574bc57385371008e7a8579c8e8.tar.gz
taler-ios-c6998563642e8574bc57385371008e7a8579c8e8.tar.bz2
taler-ios-c6998563642e8574bc57385371008e7a8579c8e8.zip
add in most wallet requests
-rw-r--r--Taler.xcodeproj/project.pbxproj16
-rw-r--r--Taler/BalanceList.swift76
-rw-r--r--Taler/BalanceRow.swift (renamed from Taler/ContentView.swift)16
-rw-r--r--Taler/SceneDelegate.swift9
-rw-r--r--Taler/WalletBackend.swift1168
-rw-r--r--TalerTests/TimestampTests.swift43
6 files changed, 1289 insertions, 39 deletions
diff --git a/Taler.xcodeproj/project.pbxproj b/Taler.xcodeproj/project.pbxproj
index 12f8c85..0943e6f 100644
--- a/Taler.xcodeproj/project.pbxproj
+++ b/Taler.xcodeproj/project.pbxproj
@@ -11,9 +11,10 @@
D1472E5526B9206800896566 /* AmountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1472E5426B9206800896566 /* AmountTests.swift */; };
D14AFD2124D232B300C51073 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14AFD2024D232B300C51073 /* AppDelegate.swift */; };
D14AFD2324D232B300C51073 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14AFD2224D232B300C51073 /* SceneDelegate.swift */; };
- D14AFD2524D232B300C51073 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14AFD2424D232B300C51073 /* ContentView.swift */; };
D14AFD3824D232B500C51073 /* TalerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14AFD3724D232B500C51073 /* TalerTests.swift */; };
D14AFD4324D232B500C51073 /* TalerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14AFD4224D232B500C51073 /* TalerUITests.swift */; };
+ D14CE1B226C39E5D00612DBE /* BalanceRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14CE1B126C39E5D00612DBE /* BalanceRow.swift */; };
+ D14CE1B426C3A2D400612DBE /* BalanceList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14CE1B326C3A2D400612DBE /* BalanceList.swift */; };
D17D8B7225ADB29A001BD43D /* libbrotli.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D17D8B4F25ADB12D001BD43D /* libbrotli.a */; };
D17D8B7325ADB29A001BD43D /* libzlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D17D8B4725ADB12B001BD43D /* libzlib.a */; };
D17D8B7425ADB29A001BD43D /* libv8_zlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D17D8B5425ADB12D001BD43D /* libv8_zlib.a */; };
@@ -34,6 +35,7 @@
D17D8B8325ADB29B001BD43D /* libllhttp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D17D8B4D25ADB12C001BD43D /* libllhttp.a */; };
D17D8B8425ADB29B001BD43D /* libhistogram.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D17D8B5625ADB130001BD43D /* libhistogram.a */; };
D17D8B8525ADB29B001BD43D /* libcares.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D17D8B4825ADB12B001BD43D /* libcares.a */; };
+ D18DBB5E26DF160D00A4480D /* TimestampTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D18DBB5D26DF160D00A4480D /* TimestampTests.swift */; };
D1AFF0F3268D59C200FBB744 /* libiono.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D1AFF0F2268D59A500FBB744 /* libiono.a */; };
D1BA3F9226B8889600A5848B /* Amount.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1BA3F9126B8889600A5848B /* Amount.swift */; };
D1D65B9826992E4600C1012A /* WalletBackend.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D65B9726992E4600C1012A /* WalletBackend.swift */; };
@@ -117,7 +119,6 @@
D14AFD1D24D232B300C51073 /* Taler.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Taler.app; sourceTree = BUILT_PRODUCTS_DIR; };
D14AFD2024D232B300C51073 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D14AFD2224D232B300C51073 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
- D14AFD2424D232B300C51073 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
D14AFD2624D232B500C51073 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
D14AFD2C24D232B500C51073 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
D14AFD2E24D232B500C51073 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -127,6 +128,8 @@
D14AFD3E24D232B500C51073 /* TalerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TalerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D14AFD4224D232B500C51073 /* TalerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TalerUITests.swift; sourceTree = "<group>"; };
D14AFD4424D232B500C51073 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ D14CE1B126C39E5D00612DBE /* BalanceRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceRow.swift; sourceTree = "<group>"; };
+ D14CE1B326C3A2D400612DBE /* BalanceList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceList.swift; sourceTree = "<group>"; };
D1595BBD25A550750049971F /* libnode.89.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libnode.89.dylib; path = "ios-node-v8/out/Debug/libnode.89.dylib"; sourceTree = "<group>"; };
D1595BC625A5527C0049971F /* NodeMobile.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NodeMobile.framework; path = "nodejs-mobile-v0.3.2-ios/Release-universal/NodeMobile.framework"; sourceTree = "<group>"; };
D17D8B4425ADB12B001BD43D /* libv8_libbase.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libv8_libbase.a; path = "ios-node-v8/taler-ios-build/compiled/node-arm64/libv8_libbase.a"; sourceTree = "<group>"; };
@@ -149,6 +152,7 @@
D17D8B5525ADB12E001BD43D /* libuvwasi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libuvwasi.a; path = "ios-node-v8/taler-ios-build/compiled/node-arm64/libuvwasi.a"; sourceTree = "<group>"; };
D17D8B5625ADB130001BD43D /* libhistogram.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libhistogram.a; path = "ios-node-v8/taler-ios-build/compiled/node-arm64/libhistogram.a"; sourceTree = "<group>"; };
D17D8B5725ADB130001BD43D /* libtorque_base.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtorque_base.a; path = "ios-node-v8/taler-ios-build/compiled/node-arm64/libtorque_base.a"; sourceTree = "<group>"; };
+ D18DBB5D26DF160D00A4480D /* TimestampTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimestampTests.swift; sourceTree = "<group>"; };
D1AB963B259EB13D00DEAB23 /* libnode.89.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libnode.89.dylib; path = "ios-node-v8/taler-ios-build/compiled/x64-v8a/libnode.89.dylib"; sourceTree = "<group>"; };
D1AFF0F2268D59A500FBB744 /* libiono.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libiono.a; path = iono/compiled/x64/libiono.a; sourceTree = "<group>"; };
D1BA3F9126B8889600A5848B /* Amount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Amount.swift; sourceTree = "<group>"; };
@@ -271,7 +275,8 @@
D14AFD2224D232B300C51073 /* SceneDelegate.swift */,
D1D65B9726992E4600C1012A /* WalletBackend.swift */,
D1BA3F9126B8889600A5848B /* Amount.swift */,
- D14AFD2424D232B300C51073 /* ContentView.swift */,
+ D14CE1B126C39E5D00612DBE /* BalanceRow.swift */,
+ D14CE1B326C3A2D400612DBE /* BalanceList.swift */,
D14AFD2624D232B500C51073 /* Assets.xcassets */,
D14AFD2B24D232B500C51073 /* LaunchScreen.storyboard */,
D14AFD2E24D232B500C51073 /* Info.plist */,
@@ -285,6 +290,7 @@
D14AFD3724D232B500C51073 /* TalerTests.swift */,
D14AFD3924D232B500C51073 /* Info.plist */,
D1472E5426B9206800896566 /* AmountTests.swift */,
+ D18DBB5D26DF160D00A4480D /* TimestampTests.swift */,
);
path = TalerTests;
sourceTree = "<group>";
@@ -588,8 +594,9 @@
D1BA3F9226B8889600A5848B /* Amount.swift in Sources */,
D14AFD2124D232B300C51073 /* AppDelegate.swift in Sources */,
D14AFD2324D232B300C51073 /* SceneDelegate.swift in Sources */,
- D14AFD2524D232B300C51073 /* ContentView.swift in Sources */,
D1D65B9826992E4600C1012A /* WalletBackend.swift in Sources */,
+ D14CE1B426C3A2D400612DBE /* BalanceList.swift in Sources */,
+ D14CE1B226C39E5D00612DBE /* BalanceRow.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -599,6 +606,7 @@
files = (
D14AFD3824D232B500C51073 /* TalerTests.swift in Sources */,
D1472E5526B9206800896566 /* AmountTests.swift in Sources */,
+ D18DBB5E26DF160D00A4480D /* TimestampTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Taler/BalanceList.swift b/Taler/BalanceList.swift
new file mode 100644
index 0000000..5e77b6c
--- /dev/null
+++ b/Taler/BalanceList.swift
@@ -0,0 +1,76 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2021 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+import SwiftUI
+
+struct IdentifiedArray<T>: RandomAccessCollection {
+ struct Item {
+ var id: Int
+ var item: T
+ }
+
+ typealias Element = Item
+ typealias ItemArray = [Item]
+ typealias Index = ItemArray.Index
+ typealias SubSequence = IdentifiedArray<T>
+ typealias Indices = ItemArray.Indices
+
+ var items: ItemArray
+ var startIndex: ItemArray.Index {
+ get {
+ return items.startIndex
+ }
+ }
+ var endIndex: ItemArray.Index {
+ get {
+ return items.endIndex
+ }
+ }
+
+ subscript(position: ItemArray.Index) -> Element {
+ get {
+ return items[position]
+ }
+ set(value) {
+ items[position] = value
+ }
+ }
+
+ init(_ array: [T]) {
+ self.items = array.enumerated().map({ (index, element) in
+ return Item(id: index, item: element)
+ })
+ }
+}
+
+struct BalanceList: View {
+ var balances: IdentifiedArray<Balance>
+
+ var body: some View {
+ List(balances, id: \.id) { balance in
+ BalanceRow(balance: balance.item)
+ }
+ }
+}
+
+struct BalanceList_Previews: PreviewProvider {
+ static var previews: some View {
+ try! BalanceList(balances: IdentifiedArray<Balance>([
+ Balance(available: Amount(fromString: "USD:0.01"), pendingIncoming: Amount(fromString: "USD:0.02"), pendingOutgoing: Amount(fromString: "USD:0.03"), requiresUserInput: true),
+ Balance(available: Amount(fromString: "EUR:0.02"), pendingIncoming: Amount(fromString: "EUR:0.01"), pendingOutgoing: Amount(fromString: "EUR:0.03"), requiresUserInput: false)
+ ]))
+ }
+}
diff --git a/Taler/ContentView.swift b/Taler/BalanceRow.swift
index 4406fc3..405a141 100644
--- a/Taler/ContentView.swift
+++ b/Taler/BalanceRow.swift
@@ -16,14 +16,22 @@
import SwiftUI
-struct ContentView: View {
+struct BalanceRow: View {
+ var balance: Balance
+
var body: some View {
- Text("Hello, World!")
+ VStack(alignment: .leading, spacing: /*@START_MENU_TOKEN@*/nil/*@END_MENU_TOKEN@*/, content: {
+ Text("Available: \(balance.available.description)")
+ Text("Pending Incoming: \(balance.pendingIncoming.description)")
+ Text("Pending Outgoing: \(balance.pendingOutgoing.description)")
+ Text("Requires User Input: \(balance.requiresUserInput.description)")
+ })
+ .padding()
}
}
-struct ContentView_Previews: PreviewProvider {
+struct BalanceRow_Previews: PreviewProvider {
static var previews: some View {
- ContentView()
+ try! BalanceRow(balance: Balance(available: Amount(fromString: "USD:0.01"), pendingIncoming: Amount(fromString: "USD:0.02"), pendingOutgoing: Amount(fromString: "USD:0.03"), requiresUserInput: true))
}
}
diff --git a/Taler/SceneDelegate.swift b/Taler/SceneDelegate.swift
index a895f65..79b086e 100644
--- a/Taler/SceneDelegate.swift
+++ b/Taler/SceneDelegate.swift
@@ -27,15 +27,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
- // Create the SwiftUI view that provides the window contents.
- let contentView = ContentView()
-
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
- let window = UIWindow(windowScene: windowScene)
- window.rootViewController = UIHostingController(rootView: contentView)
+ /*let window = UIWindow(windowScene: windowScene)
+ window.rootViewController = UIHostingController(rootView: /* */)
self.window = window
- window.makeKeyAndVisible()
+ window.makeKeyAndVisible()*/
}
}
diff --git a/Taler/WalletBackend.swift b/Taler/WalletBackend.swift
index d5cc3ab..f1b462f 100644
--- a/Taler/WalletBackend.swift
+++ b/Taler/WalletBackend.swift
@@ -83,20 +83,40 @@ fileprivate struct WalletBackendInitRequest: WalletBackendRequest {
}
}
-fileprivate struct WalletBackendGetTransactionsRequest: WalletBackendRequest {
+/**
+ An balance on a wallet.
+ */
+struct Balance: Decodable {
+ var available: Amount
+ var pendingIncoming: Amount
+ var pendingOutgoing: Amount
+ var requiresUserInput: Bool
+}
+
+/**
+ A request to get the balances held in the wallet.
+ */
+class WalletBackendGetBalancesRequest: WalletBackendRequest {
+ struct BalancesResponse: Decodable {
+ var balances: [Balance]
+ }
struct RequestArgs: Encodable {
}
typealias Args = RequestArgs
- typealias Response = String
+ typealias Response = BalancesResponse
private var requestArgs: RequestArgs
+ private let success: ([Balance]) -> Void
+ private let failure: () -> Void
- init() {
- requestArgs = RequestArgs()
+ init(onSuccess: @escaping ([Balance]) -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs()
+ self.success = onSuccess
+ self.failure = onFailure
}
func operation() -> String {
- return "getTransactions"
+ return "getBalances"
}
func args() -> Args {
@@ -104,41 +124,312 @@ fileprivate struct WalletBackendGetTransactionsRequest: WalletBackendRequest {
}
func success(result: Response) {
-
+ self.success(result.balances)
}
func error(_ err: WalletBackendResponseError) {
-
+ self.failure()
}
}
-struct WalletBackendGetBalancesRequest: WalletBackendRequest {
- struct Balance: Decodable {
- var available: Amount
- var pendingIncoming: Amount
- var pendingOutgoing: Amount
- var requiresUserInput: Bool
+/**
+ A timestamp, measured in milliseconds elapsed from an epoch.
+ */
+enum TimestampError: Error {
+ case invalidString
+}
+
+enum Timestamp: Codable, Equatable {
+ case millisecondsSinceEpoch(Int)
+ case never
+
+ enum CodingKeys: String, CodingKey {
+ case t_ms = "t_ms"
}
- struct BalancesResponse: Decodable {
- var balances: [Balance]
+
+ init(from decoder: Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+ do {
+ self = Timestamp.millisecondsSinceEpoch(try container.decode(Int.self, forKey: .t_ms))
+ } catch {
+ let stringValue = try container.decode(String.self, forKey: .t_ms)
+ if stringValue == "never" {
+ self = Timestamp.never
+ } else {
+ throw TimestampError.invalidString
+ }
+ }
}
+
+ func encode(to encoder: Encoder) throws {
+ var value = encoder.singleValueContainer()
+ switch self {
+ case .millisecondsSinceEpoch(let t_ms):
+ try value.encode(t_ms)
+ case .never:
+ try value.encode("never")
+ }
+ }
+}
+
+/**
+ A billing or mailing location.
+ */
+struct Location: Codable {
+ var country: String?
+ var country_subdivision: String?
+ var district: String?
+ var town: String?
+ var town_location: String?
+ var post_code: String?
+ var street: String?
+ var building_name: String?
+ var building_number: String?
+ var address_lines: [String]?
+}
+
+/**
+ Information identifying a merchant.
+ */
+struct Merchant: Codable {
+ var name: String
+ var address: Location?
+ var jurisdiction: Location?
+}
+
+/**
+ A tax made on a payment.
+ */
+struct Tax: Codable {
+ var name: String
+ var tax: Amount
+}
+
+/**
+ A product being purchased from a merchant.
+ */
+struct Product: Codable {
+ var product_id: String?
+ var description: String
+ // description_i18n?
+ var quantity: Int
+ var unit: String
+ var price: Amount?
+ var image: String // URL to a product image
+ var taxes: [Tax]?
+ var delivery_date: Timestamp?
+}
+
+/**
+ Brief information about an order.
+ */
+struct OrderShortInfo: Codable {
+ var orderId: String
+ var merchant: Merchant
+ var summary: String
+ // summary_i18n?
+ var products: [Product]
+ var fulfillmentUrl: String?
+ var fulfillmentMessage: String?
+ // fulfillmentMessage_i18n?
+}
+
+enum TransactionTypeError: Error {
+ case unknownTypeError
+}
+
+/**
+ Different types of transactions.
+ */
+enum TransactionType: Codable {
+ case withdrawal
+ case payment
+ case refund
+ case tip
+ case refresh
+
+ init(from decoder: Decoder) throws {
+ let value = try decoder.singleValueContainer()
+ let str = try value.decode(String.self)
+ let codingNames = [
+ "TransactionWithdrawal" : TransactionType.withdrawal,
+ "TransactionPayment" : TransactionType.payment,
+ "TransactionRefund" : TransactionType.refund,
+ "TransactionTip" : TransactionType.tip,
+ "TransactionRefresh" : TransactionType.refresh
+ ]
+ if let type = codingNames[str] {
+ self = type
+ } else {
+ throw TransactionTypeError.unknownTypeError
+ }
+ }
+
+ func encode(to encoder: Encoder) throws {
+ var value = encoder.singleValueContainer()
+ switch self {
+ case .withdrawal:
+ try value.encode("TransactionWithdrawal")
+ case .payment:
+ try value.encode("TransactionPayment")
+ case .refund:
+ try value.encode("TransactionRefund")
+ case .tip:
+ try value.encode("TransactionTip")
+ case .refresh:
+ try value.encode("TransactionRefresh")
+ }
+ }
+}
+
+/**
+ An error associated with a transaction.
+ */
+struct TransactionError: Codable {
+ var ec: Int
+ var hint: String?
+ //var details: Any?
+}
+
+/**
+ A wallet transaction.
+ */
+struct Transaction: Codable {
+ var transactionId: String
+ var type: TransactionType
+ var timestamp: Timestamp
+ var pending: Bool
+ var error: TransactionError?
+ var amountRaw: Amount
+ var amountEffective: Amount
+}
+
+/**
+ A request to get the transactions in the wallet's history.
+ */
+class WalletBackendGetTransactionsRequest: WalletBackendRequest {
struct RequestArgs: Encodable {
+ var currency: String?
+ var search: String?
+ }
+ struct TransactionsResponse: Decodable {
}
typealias Args = RequestArgs
- typealias Response = BalancesResponse
+ typealias Response = TransactionsResponse
private var requestArgs: RequestArgs
- private let success: ([Balance]) -> Void
+ private let success: () -> Void
private let failure: () -> Void
- init(onSuccess: @escaping ([Balance]) -> Void, onFailure: @escaping () -> Void) {
- self.requestArgs = RequestArgs()
+ init(onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(currency: nil, search: nil)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ init(filterCurrency: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(currency: filterCurrency, search: nil)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ init(searchString: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(currency: nil, search: searchString)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ init(filterCurrency: String, searchString: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(currency: filterCurrency, search: searchString)
self.success = onSuccess
self.failure = onFailure
}
func operation() -> String {
- return "getBalances"
+ return "getTransactions"
+ }
+
+ func args() -> Args {
+ return requestArgs
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to delete a wallet transaction by ID.
+ */
+class WalletBackendDeleteTransactionRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var transactionId: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private var requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(transactionID: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(transactionId: transactionID)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "deleteTransaction"
+ }
+
+ func args() -> Args {
+ return requestArgs
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to process a refund.
+ */
+class WalletBackendApplyRefundRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var talerRefundUri: String
+ }
+ struct RequestResponse: Decodable {
+ var contractTermsHash: String
+ var amountEffectivePaid: Amount
+ var amountRefundGranted: Amount
+ var amountRefundGone: Amount
+ var pendingAtExchange: Bool
+ var info: OrderShortInfo
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: (RequestResponse) -> Void
+ private let failure: () -> Void
+
+ init(refundURI: String, onSuccess: @escaping (RequestResponse) -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(talerRefundUri: refundURI)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "applyRefund"
}
func args() -> Args {
@@ -146,17 +437,667 @@ struct WalletBackendGetBalancesRequest: WalletBackendRequest {
}
func success(result: Response) {
- print("balances???")
+ self.success(result)
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to list exchanges.
+ */
+class WalletBackendListExchanges: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+
+ }
+ struct ExchangeListItem: Decodable {
+ var exchangeBaseUrl: String
+ var currency: String
+ var paytoUris: [String]
+ }
+ struct RequestResponse: Decodable {
+ var exchanges: [ExchangeListItem]
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let success: ([ExchangeListItem]) -> Void
+ private let failure: () -> Void
+
+ init(onSuccess: @escaping ([ExchangeListItem]) -> Void, onFailure: @escaping () -> Void) {
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "listExchanges"
+ }
+
+ func args() -> RequestArgs {
+ return RequestArgs()
+ }
+
+ func success(result: RequestResponse) {
+ self.success(result.exchanges)
}
func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to add an exchange.
+ */
+class WalletBackendAddRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var exchangeBaseUrl: String
+ }
+ struct RequestResponse: Decodable {
}
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "addRequest"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
}
-struct WalletBackendWithdrawTestBalance: WalletBackendRequest {
+/**
+ A request to force update an exchange.
+ */
+class WalletBackendForceUpdateRequest: WalletBackendRequest {
struct RequestArgs: Encodable {
- var amount: String
+ var exchangeBaseUrl: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "addRequest"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to query an exchange's terms of service.
+ */
+class WalletBackendGetExchangeTermsOfService: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var exchangeBaseUrl: String
+ }
+ struct RequestResponse: Decodable {
+ var tos: String
+ var currentEtag: String
+ var acceptedEtag: String
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "getExchangeTos"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to mark an exchange's terms of service as accepted.
+ */
+class WalletBackendSetExchangeTermsOfServiceAccepted: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var exchangeBaseUrl: String
+ var acceptedEtag: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(exchangeBaseURL: String, acceptedEtag: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL, acceptedEtag: acceptedEtag)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "setExchangeTosAccepted"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+struct ExchangeListItem: Codable {
+ var exchangeBaseUrl: String
+ var currency: String
+ var paytoUris: [String]
+}
+
+/**
+ A request to get an exchange's withdrawal details.
+ */
+class WalletBackendGetWithdrawalDetailsForURIRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var talerWithdrawUri: String
+ }
+ struct RequestResponse: Decodable {
+ var amount: Amount
+ var defaultExchangeBaseUrl: String?
+ var possibleExchanges: [ExchangeListItem]
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(talerWithdrawUri: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(talerWithdrawUri: talerWithdrawUri)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "getWithdrawalDetailsForUri"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to get an exchange's withdrawal details.
+ */
+class WalletBackendGetWithdrawalDetailsForAmountRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var exchangeBaseUrl: String
+ var amount: Amount
+ }
+ struct RequestResponse: Decodable {
+ var tosAccepted: Bool
+ var amountRaw: Amount
+ var amountEffective: Amount
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(exchangeBaseURL: String, amount: Amount, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL, amount: amount)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "getWithdrawalDetailsForAmount"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to accept a bank-integrated withdrawl.
+ */
+class WalletBackendAcceptBankIntegratedWithdrawalRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var talerWithdrawUri: String
+ var exchangeBaseUrl: String
+ }
+ struct RequestResponse: Decodable {
+ var bankConfirmationUrl: String?
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(talerWithdrawURI: String, exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(talerWithdrawUri: talerWithdrawURI, exchangeBaseUrl: exchangeBaseURL)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "acceptWithdrawal"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to accept a manual withdrawl.
+ */
+class WalletBackendAcceptManualWithdrawalRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var exchangeBaseUrl: String
+ var amount: Amount
+ }
+ struct RequestResponse: Decodable {
+ var exchangePaytoUris: [String]
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(exchangeBaseURL: String, amount: Amount, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL, amount: amount)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "acceptManualWithdrawal"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to deposit funds.
+ */
+class WalletBackendCreateDepositGroupRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var depositPayToUri: String
+ var amount: Amount
+ }
+ struct RequestResponse: Decodable {
+ var depositGroupId: String
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(depositPayToUri: String, amount: Amount, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(depositPayToUri: depositPayToUri, amount: amount)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "createDepositGroup"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to get information about a payment request.
+ */
+class WalletBackendPreparePayRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var talerPayUri: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(talerPayUri: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(talerPayUri: talerPayUri)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "preparePay"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to confirm a payment.
+ */
+class WalletBackendConfirmPayRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var proposalId: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(proposalId: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(proposalId: proposalId)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "abortFailedPayWithRefund"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to prepare a tip.
+ */
+class WalletBackendPrepareTipRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var talerTipUri: String
+ }
+ struct RequestResponse: Decodable {
+ var walletTipId: String
+ var accepted: Bool
+ var tipAmountRaw: Amount
+ var tipAmountEffective: Amount
+ var exchangeBaseUrl: String
+ var expirationTimestamp: Timestamp
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(talerTipURI: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(talerTipUri: talerTipURI)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "prepareTip"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to accept a tip.
+ */
+class WalletBackendAcceptTipRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var walletTipId: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(walletTipId: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(walletTipId: walletTipId)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "acceptTip"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to abort a failed payment.
+ */
+class WalletBackendAbortFailedPaymentRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var proposalId: String
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(proposalId: String, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(proposalId: proposalId)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "confirmPay"
+ }
+
+ func args() -> RequestArgs {
+ return requestArgs
+ }
+
+ func success(result: RequestResponse) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to withdraw a balance from the TESTKUDOS environment.
+ */
+class WalletBackendWithdrawTestkudosRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "withdrawTestkudos"
+ }
+
+ func args() -> Args {
+ return RequestArgs()
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to add a test balance to the wallet.
+ */
+class WalletBackendWithdrawTestBalance: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var amount: Amount
var bankBaseUrl: String
var exchangeBaseUrl: String
}
@@ -164,7 +1105,7 @@ struct WalletBackendWithdrawTestBalance: WalletBackendRequest {
typealias Response = String
private var requestArgs: RequestArgs
- init(amount: String, bankBaseUrl: String, exchangeBaseUrl: String) {
+ init(amount: Amount, bankBaseUrl: String, exchangeBaseUrl: String) {
requestArgs = RequestArgs(amount: amount, bankBaseUrl: bankBaseUrl, exchangeBaseUrl: exchangeBaseUrl)
}
@@ -185,6 +1126,183 @@ struct WalletBackendWithdrawTestBalance: WalletBackendRequest {
}
}
+struct IntegrationTestArgs: Codable {
+ var exchangeBaseUrl: String
+ var bankBaseUrl: String
+ var merchantBaseUrl: String
+ var merchantApiKey: String
+ var amountToWithdraw: String
+ var amountToSpend: String
+}
+
+/**
+ A request to run a basic integration test.
+ */
+class WalletBackendRunIntegrationTestRequest: WalletBackendRequest {
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = IntegrationTestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: IntegrationTestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(args: IntegrationTestArgs, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = args
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "runIntegrationTest"
+ }
+
+ func args() -> Args {
+ return requestArgs
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+struct TestPayArgs: Codable {
+ var merchantBaseUrl: String
+ var merchantApiKey: String
+ var amount: String
+ var summary: String
+}
+
+/**
+ A request to make a test payment.
+ */
+class WalletBackendTestPayRequest: WalletBackendRequest {
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = TestPayArgs
+ typealias Response = RequestResponse
+ private let requestArgs: TestPayArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(args: TestPayArgs, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = args
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "testPay"
+ }
+
+ func args() -> Args {
+ return requestArgs
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+struct Coin: Codable {
+ var denom_pub: String
+ var denom_pub_hash: String
+ var denom_value: String
+ var coin_pub: String
+ var exchange_base_url: String
+ var remaining_value: String
+ var refresh_parent_coin_pub: String
+ var withdrawal_reserve_pub: String
+ var coin_suspended: Bool
+}
+
+/**
+ A request to dump all coins to JSON.
+ */
+class WalletBackendDumpCoinsRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+
+ }
+ struct RequestResponse: Decodable {
+ var coins: [Coin]
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "dumpCoins"
+ }
+
+ func args() -> Args {
+ return RequestArgs()
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
+/**
+ A request to suspend or unsuspend a coin.
+ */
+class WalletBackendSuspendCoinRequest: WalletBackendRequest {
+ struct RequestArgs: Encodable {
+ var coinPub: String
+ var suspended: Bool
+ }
+ struct RequestResponse: Decodable {
+
+ }
+ typealias Args = RequestArgs
+ typealias Response = RequestResponse
+ private let requestArgs: RequestArgs
+ private let success: () -> Void
+ private let failure: () -> Void
+
+ init(coinPub: String, suspended: Bool, onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
+ self.requestArgs = RequestArgs(coinPub: coinPub, suspended: suspended)
+ self.success = onSuccess
+ self.failure = onFailure
+ }
+
+ func operation() -> String {
+ return "setCoinSuspended"
+ }
+
+ func args() -> Args {
+ return requestArgs
+ }
+
+ func success(result: Response) {
+ self.success()
+ }
+
+ func error(_ err: WalletBackendResponseError) {
+ self.failure()
+ }
+}
+
enum WalletBackendError: Error {
case serializationError
case deserializationError
@@ -234,7 +1352,7 @@ class WalletBackend: IonoMessageHandler {
waitUntilReady()
//try! sendRequest(request: WalletBackendWithdrawTestBalance(amount: "TESTKUDOS:10", bankBaseUrl: "https://bank.test.taler.net/", exchangeBaseUrl: "https://exchange.test.taler.net/"))
- try! sendRequest(request: WalletBackendGetBalancesRequest(onSuccess: { ([WalletBackendGetBalancesRequest.Balance]) -> Void in
+ try! sendRequest(request: WalletBackendGetBalancesRequest(onSuccess: { ([Balance]) -> Void in
}, onFailure: { () -> Void in
diff --git a/TalerTests/TimestampTests.swift b/TalerTests/TimestampTests.swift
new file mode 100644
index 0000000..d2b2433
--- /dev/null
+++ b/TalerTests/TimestampTests.swift
@@ -0,0 +1,43 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2021 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+import XCTest
+@testable import Taler
+
+class TimestampTests: XCTestCase {
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+ func testTimestamps() throws {
+ let json1 = "{ \"t_ms\" : 12309487 }".data(using: .utf8)!
+ let json2 = "{ \"t_ms\" : \"never\" }".data(using: .utf8)!
+ let json3 = "{ \"t_ms\" : \"sometime\" }".data(using: .utf8)!
+
+ var t: Timestamp = try! JSONDecoder().decode(Timestamp.self, from: json1)
+ XCTAssertEqual(t, Timestamp.millisecondsSinceEpoch(12309487))
+
+ t = try! JSONDecoder().decode(Timestamp.self, from: json2)
+ XCTAssertEqual(t, Timestamp.never)
+ XCTAssertThrowsError(t = try JSONDecoder().decode(Timestamp.self, from: json3))
+ }
+
+}