Skip to content

Commit 748ba62

Browse files
authored
Merge pull request #1234 from tari-project/exolix-finalisation
Exolix RC
2 parents dece90f + 064c59e commit 748ba62

23 files changed

+444
-190
lines changed

MobileWallet.xcodeproj/project.pbxproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@
534534
F8472F6B2E69BBCB0094163D /* SendingTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8472F6A2E69BBCB0094163D /* SendingTransaction.swift */; };
535535
F8472F6D2E744AFF0094163D /* SendingTransaction+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8472F6C2E744AFA0094163D /* SendingTransaction+Actions.swift */; };
536536
F8472F722E745A3E0094163D /* ProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8472F712E745A3D0094163D /* ProgressIndicator.swift */; };
537+
F849ACB62ED5D024005B38AF /* SwapInProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = F849ACB52ED5D01C005B38AF /* SwapInProgress.swift */; };
538+
F849ACBA2ED5F823005B38AF /* CodableStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F849ACB92ED5F822005B38AF /* CodableStorage.swift */; };
537539
F88781AF2EB10B1E00207D0B /* TokenPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88781AE2EB10B1E00207D0B /* TokenPicker.swift */; };
538540
F88781B12EB1EC5A00207D0B /* SwapDeposit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88781B02EB1EC5A00207D0B /* SwapDeposit.swift */; };
539541
F88781B32EB1EE4C00207D0B /* SwapProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88781B22EB1EE4C00207D0B /* SwapProgress.swift */; };
@@ -1130,6 +1132,8 @@
11301132
F8472F6A2E69BBCB0094163D /* SendingTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendingTransaction.swift; sourceTree = "<group>"; };
11311133
F8472F6C2E744AFA0094163D /* SendingTransaction+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SendingTransaction+Actions.swift"; sourceTree = "<group>"; };
11321134
F8472F712E745A3D0094163D /* ProgressIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressIndicator.swift; sourceTree = "<group>"; };
1135+
F849ACB52ED5D01C005B38AF /* SwapInProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapInProgress.swift; sourceTree = "<group>"; };
1136+
F849ACB92ED5F822005B38AF /* CodableStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableStorage.swift; sourceTree = "<group>"; };
11331137
F88781AE2EB10B1E00207D0B /* TokenPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenPicker.swift; sourceTree = "<group>"; };
11341138
F88781B02EB1EC5A00207D0B /* SwapDeposit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapDeposit.swift; sourceTree = "<group>"; };
11351139
F88781B22EB1EE4C00207D0B /* SwapProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapProgress.swift; sourceTree = "<group>"; };
@@ -1907,6 +1911,7 @@
19071911
545A9D22294F9E66008D24A6 /* User Settings */,
19081912
37B48A8224B3968F00F8A8D2 /* AppKeychainWrapper.swift */,
19091913
3A4CE32F26A18DFC00ECF460 /* UserDefaults.swift */,
1914+
F849ACB92ED5F822005B38AF /* CodableStorage.swift */,
19101915
);
19111916
path = "Persistant Data";
19121917
sourceTree = "<group>";
@@ -3036,6 +3041,7 @@
30363041
F82888B22EC39D730085A103 /* Models */ = {
30373042
isa = PBXGroup;
30383043
children = (
3044+
F849ACB52ED5D01C005B38AF /* SwapInProgress.swift */,
30393045
F82888B32EC39D7B0085A103 /* ExolixConfirmation.swift */,
30403046
);
30413047
path = Models;
@@ -3633,6 +3639,7 @@
36333639
3AE5E5682874696E00D3AF85 /* ValuePickerView.swift in Sources */,
36343640
3A0391E6290BA40E00352D73 /* BugReportingView.swift in Sources */,
36353641
546B032A2983F33600DBED8E /* OnboardingPagerView.swift in Sources */,
3642+
F849ACB62ED5D024005B38AF /* SwapInProgress.swift in Sources */,
36363643
54E007B62B8DF55600AFCD7C /* SecurityManager.swift in Sources */,
36373644
711D7FA42D511FDE0080A987 /* LogViewController.swift in Sources */,
36383645
71F2B2232D8C20E700104073 /* LoginDeeplink.swift in Sources */,
@@ -3744,6 +3751,7 @@
37443751
5422CBFC2B88C79200428394 /* ScreenRecordingSettingsView.swift in Sources */,
37453752
711F28EB2DA3322D00751986 /* ReceiveViewController.swift in Sources */,
37463753
711D7FA82D5503540080A987 /* StylisedButton.swift in Sources */,
3754+
F849ACBA2ED5F823005B38AF /* CodableStorage.swift in Sources */,
37473755
37547D5624601BF600EB59CC /* UIView+GlobalFrame.swift in Sources */,
37483756
54D46A952CA6909800E554C0 /* WalletTag.swift in Sources */,
37493757
BF8316FD23EF7EAA00235403 /* LAContext.swift in Sources */,
@@ -4125,7 +4133,7 @@
41254133
CODE_SIGN_ENTITLEMENTS = MobileWallet/Tari.entitlements;
41264134
CODE_SIGN_IDENTITY = "Apple Development";
41274135
CODE_SIGN_STYLE = Automatic;
4128-
CURRENT_PROJECT_VERSION = Dev;
4136+
CURRENT_PROJECT_VERSION = 5;
41294137
DEVELOPMENT_TEAM = 8XGMD9X2H2;
41304138
ENABLE_BITCODE = NO;
41314139
FRAMEWORK_SEARCH_PATHS = (
@@ -4160,7 +4168,7 @@
41604168
CODE_SIGN_ENTITLEMENTS = MobileWallet/Tari.entitlements;
41614169
CODE_SIGN_IDENTITY = "Apple Development";
41624170
CODE_SIGN_STYLE = Automatic;
4163-
CURRENT_PROJECT_VERSION = Dev;
4171+
CURRENT_PROJECT_VERSION = 5;
41644172
DEVELOPMENT_TEAM = 8XGMD9X2H2;
41654173
ENABLE_BITCODE = NO;
41664174
FRAMEWORK_SEARCH_PATHS = (

MobileWallet/Common/APIService.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ private extension API {
104104
if httpResponse.statusCode == 401 {
105105
throw APIError.unauthorized
106106
}
107-
if let responseString = String(data: data, encoding: .utf8) {
108-
print("API Response for \(endpoint): \(responseString)")
109-
}
110107
}
111108

112109
func refreshToken() async throws {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// CodableStorage.swift
2+
3+
/*
4+
Package MobileWallet
5+
Created by Tomas Hakel on 25.11.2025
6+
Using Swift 6.0
7+
Running on macOS 26.0
8+
9+
Copyright 2019 The Tari Project
10+
11+
Redistribution and use in source and binary forms, with or
12+
without modification, are permitted provided that the
13+
following conditions are met:
14+
15+
1. Redistributions of source code must retain the above copyright notice,
16+
this list of conditions and the following disclaimer.
17+
18+
2. Redistributions in binary form must reproduce the above
19+
copyright notice, this list of conditions and the following disclaimer in the
20+
documentation and/or other materials provided with the distribution.
21+
22+
3. Neither the name of the copyright holder nor the names of
23+
its contributors may be used to endorse or promote products
24+
derived from this software without specific prior written permission.
25+
26+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
27+
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
28+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
31+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
37+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39+
*/
40+
41+
import SwiftUI
42+
43+
@propertyWrapper
44+
public struct CodableStorage<Value: Codable>: DynamicProperty {
45+
public init(
46+
_ key: String,
47+
store: UserDefaults = .standard,
48+
defaultValue: Value
49+
) {
50+
self.key = key
51+
self.store = store
52+
self.defaultValue = defaultValue
53+
}
54+
55+
private let defaultValue: Value
56+
private let key: String
57+
private let store: UserDefaults
58+
59+
public var wrappedValue: Value {
60+
get {
61+
Self.initialValue(for: key, in: store) ?? defaultValue
62+
}
63+
nonmutating set {
64+
let data = try? JSONEncoder().encode(newValue)
65+
store.set(data, forKey: key)
66+
}
67+
}
68+
}
69+
70+
private extension CodableStorage {
71+
static func initialValue(
72+
for key: String,
73+
in store: UserDefaults
74+
) -> Value? {
75+
guard let data = store.object(forKey: key) as? Data else { return nil }
76+
return try? JSONDecoder().decode(Value.self, from: data)
77+
}
78+
}

MobileWallet/Common/Persistant Data/UserDefaults.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import Foundation
4242

4343
// MARK: - Generic User Defaults
4444

45-
private enum UserDefaultName: String, CaseIterable {
45+
enum UserDefaultName: String, CaseIterable {
4646
case selectedNetworkName
4747
case networksSettings
4848
case walletSettings
@@ -53,13 +53,13 @@ private enum UserDefaultName: String, CaseIterable {
5353
}
5454

5555
enum GroupUserDefaults {
56-
@UserDefault(key: UserDefaultName.selectedNetworkName.rawValue, suiteName: TariSettings.groupIndentifier) static var selectedNetworkName: String?
57-
@UserDefault(key: UserDefaultName.networksSettings.rawValue, suiteName: TariSettings.groupIndentifier) static var networksSettings: [NetworkSettings]?
58-
@UserDefault(key: UserDefaultName.walletSettings.rawValue, suiteName: TariSettings.groupIndentifier) static var walletSettings: [WalletSettings]?
59-
@UserDefault(key: UserDefaultName.userSettings.rawValue, suiteName: TariSettings.groupIndentifier) static var userSettings: UserSettings?
60-
@UserDefault(key: UserDefaultName.isTrackingEnabled.rawValue, suiteName: TariSettings.groupIndentifier) static var isTrackingEnabled: Bool?
61-
@UserDefault(key: UserDefaultName.areScreenshotsDisabled.rawValue, suiteName: TariSettings.groupIndentifier) static var areScreenshotsDisabled: Bool?
62-
@UserDefault(key: UserDefaultName.trustedAddresses.rawValue, suiteName: TariSettings.groupIndentifier) static var trustedAddresses: Set<String>?
56+
@UserDefault(key: UserDefaultName.selectedNetworkName, suiteName: TariSettings.groupIndentifier) static var selectedNetworkName: String?
57+
@UserDefault(key: UserDefaultName.networksSettings, suiteName: TariSettings.groupIndentifier) static var networksSettings: [NetworkSettings]?
58+
@UserDefault(key: UserDefaultName.walletSettings, suiteName: TariSettings.groupIndentifier) static var walletSettings: [WalletSettings]?
59+
@UserDefault(key: UserDefaultName.userSettings, suiteName: TariSettings.groupIndentifier) static var userSettings: UserSettings?
60+
@UserDefault(key: UserDefaultName.isTrackingEnabled, suiteName: TariSettings.groupIndentifier) static var isTrackingEnabled: Bool?
61+
@UserDefault(key: UserDefaultName.areScreenshotsDisabled, suiteName: TariSettings.groupIndentifier) static var areScreenshotsDisabled: Bool?
62+
@UserDefault(key: UserDefaultName.trustedAddresses, suiteName: TariSettings.groupIndentifier) static var trustedAddresses: Set<String>?
6363
}
6464

6565
// MARK: - Extensions

MobileWallet/Common/Property Wrappers/UserDefault.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ import Foundation
4343
@propertyWrapper struct UserDefault<T: Codable> {
4444
private let key: String
4545
private let userDefaults: UserDefaults
46+
47+
init(key: UserDefaultName, suiteName: String? = nil) {
48+
self.init(key.rawValue, suiteName: suiteName)
49+
}
4650

47-
init(key: String, suiteName: String? = nil) {
51+
init(_ key: String, suiteName: String? = nil) {
4852
self.key = key
4953
userDefaults = UserDefaults(suiteName: suiteName) ?? UserDefaults.standard
5054
}

MobileWallet/Screens/Home/Home/Scenes/Home+Actions.swift

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -202,28 +202,9 @@ private extension Home {
202202
}
203203

204204
extension Home: SwapTransactionMonitoring {
205-
var latestTransaction: ExolixTransactionResponse? {
206-
get { swapTransaction }
207-
nonmutating set { swapTransaction = newValue }
208-
}
209-
210-
var isTransactionProcessed: Bool {
211-
swapTransaction?.isProcessed == true
212-
}
213-
214-
var isTransactionCancelled: Bool {
215-
false
216-
}
217-
218-
func finaliseTransaction() {
219-
swapTransaction = nil
220-
swapInProgressId = nil
221-
}
222-
223205
func loadSwapInProgress() {
224-
guard let swapInProgressId else { return }
225206
Task {
226-
await monitorTransactionStatus(transactionId: swapInProgressId)
207+
await monitorSwapTransactions(swapTransactions)
227208
}
228209
}
229210
}

MobileWallet/Screens/Home/Home/Scenes/Home.swift

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ import SwiftUI
4242
import Combine
4343

4444
struct Home: View, ChainTipObserver {
45-
@AppStorage("swapInProgressId") var swapInProgressId: String?
45+
@CodableStorage("swapTransactions", defaultValue: SwapTransactionList()) var swapTransactions
4646
@ObservedObject var network = NetworkManager.shared
4747
@Environment(SheetRouter.self) var router
48+
@Environment(\.scenePhase) var scenePhase
4849
@State var activeMiners = " "
4950
@State var totalBalance = ""
5051
@State var availableBalance = ""
@@ -60,8 +61,8 @@ struct Home: View, ChainTipObserver {
6061
@State var isReceivePresented = false
6162
@State var isTransactionHistoryPresented = false
6263
@State var isConnectionStatusPresented = false
64+
@State var exolix = Exolix.shared
6365

64-
let exolix = Exolix()
6566
let walletState: WalletState
6667

6768
var body: some View {
@@ -72,9 +73,7 @@ struct Home: View, ChainTipObserver {
7273
miningStatus
7374
VStack(spacing: 24) {
7475
wallet
75-
if let swapTransaction {
76-
swapInProgress(swapTransaction)
77-
}
76+
swapInProgress
7877
recentActivity
7978
}
8079
}
@@ -108,7 +107,7 @@ struct Home: View, ChainTipObserver {
108107
}
109108
.fullScreenCover(item: $presentedSwapProgress) { transaction in
110109
NavigationStack {
111-
SwapProgress(exolix: Exolix(), transaction: transaction)
110+
SwapProgress(transaction: transaction)
112111
}
113112
}
114113
.sheet(isPresented: $isConnectionStatusPresented) {
@@ -122,9 +121,18 @@ struct Home: View, ChainTipObserver {
122121
.onReceive(Tari.mainWallet.transactions.$all) {
123122
update(transactions: $0)
124123
}
125-
.onChange(of: swapInProgressId) {
124+
.onChange(of: swapTransactions) {
126125
loadSwapInProgress()
127126
}
127+
.onChange(of: scenePhase) {
128+
Task {
129+
if scenePhase == .active {
130+
await exolix.monitor(transactions: Array(swapTransactions.swaps))
131+
} else {
132+
await exolix.stopMonitoringTransactions()
133+
}
134+
}
135+
}
128136
}
129137
}
130138
}
@@ -259,12 +267,18 @@ private extension Home {
259267
.foregroundStyle(.primaryText)
260268
}
261269

262-
func swapInProgress(_ swapTransaction: ExolixTransactionResponse) -> some View {
263-
VStack {
264-
sectionHeader("Swap in progress")
265-
.frame(maxWidth: .infinity, alignment: .leading)
266-
SwapInProgressItem(transaction: swapTransaction) {
267-
presentedSwapProgress = swapTransaction
270+
@ViewBuilder
271+
var swapInProgress: some View {
272+
let transactions = exolix.sortedTransactions
273+
if !transactions.isEmpty {
274+
VStack {
275+
sectionHeader("Recent Swaps")
276+
.frame(maxWidth: .infinity, alignment: .leading)
277+
ForEach(transactions) { swapTransaction in
278+
SwapInProgressItem(transaction: swapTransaction) {
279+
presentedSwapProgress = swapTransaction
280+
}
281+
}
268282
}
269283
}
270284
}

MobileWallet/Screens/Swaps/Interactors/SwapTransactionMonitoring.swift

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,18 @@
4040

4141
protocol SwapTransactionMonitoring {
4242
var exolix: Exolix { get }
43-
var latestTransaction: ExolixTransactionResponse? { get nonmutating set }
44-
var isTransactionProcessed: Bool { get }
45-
var isTransactionCancelled: Bool { get }
46-
func finaliseTransaction()
4743
}
4844

4945
extension SwapTransactionMonitoring {
50-
func monitorTransactionStatus(transactionId: String) async {
51-
guard let transaction = try? await exolix.getTransaction(id: transactionId) else { return }
52-
latestTransaction = transaction
53-
if isTransactionProcessed {
54-
finaliseTransaction()
55-
} else if !isTransactionCancelled {
56-
Task(after: 10) {
57-
if transaction.id == latestTransaction?.id {
58-
await monitorTransactionStatus(transactionId: transactionId)
59-
}
60-
}
61-
}
46+
func monitorSwapTransaction(id: String) async {
47+
await exolix.monitor(transactions: [id])
48+
}
49+
50+
func monitorSwapTransactions(_ transactions: SwapTransactionList) async {
51+
await exolix.monitor(transactions: Array(transactions.swaps))
52+
}
53+
54+
func latestTransaction(id: String) -> ExolixTransactionResponse? {
55+
exolix.latestTransaction(id: id)
6256
}
6357
}

0 commit comments

Comments
 (0)