From 02ffb137926abd0813d59cebe30b348937886312 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 2 Jul 2024 15:52:32 +0200 Subject: [PATCH 01/28] savepoint --- Package.swift | 3 ++ Sources/Events/Event.swift | 20 ++++++++ Sources/Events/EventStorage.swift | 36 ++++++++++++++ Sources/Events/EventsClient.swift | 48 +++++++++++++++++++ .../NewPairingExecutionTraceEvents.swift | 30 ++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 Sources/Events/Event.swift create mode 100644 Sources/Events/EventStorage.swift create mode 100644 Sources/Events/EventsClient.swift create mode 100644 Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift diff --git a/Package.swift b/Package.swift index b255c6b99..6667cedb9 100644 --- a/Package.swift +++ b/Package.swift @@ -126,6 +126,9 @@ let package = Package( .target( name: "Database", dependencies: ["WalletConnectUtils"]), + .target( + name: "Events", + dependencies: []), .target( name: "WalletConnectModal", dependencies: ["QRCode", "WalletConnectSign"], diff --git a/Sources/Events/Event.swift b/Sources/Events/Event.swift new file mode 100644 index 000000000..29b2f8e13 --- /dev/null +++ b/Sources/Events/Event.swift @@ -0,0 +1,20 @@ +import Foundation + + +struct Event: Codable { + let eventId: String + let bundleId: String + let timestamp: Int64 + let props: Props +} + +struct Props: Codable { + let event: String + let type: String + let properties: Properties? +} + +struct Properties: Codable { + let topic: String? + let trace: [String]? +} diff --git a/Sources/Events/EventStorage.swift b/Sources/Events/EventStorage.swift new file mode 100644 index 000000000..4622c5dcb --- /dev/null +++ b/Sources/Events/EventStorage.swift @@ -0,0 +1,36 @@ +// + +import Foundation + + +// Protocol for EventStorage +protocol EventStorage { + func saveErrorTrace(_ trace: [String]) + func fetchErrorTraces() -> [[String]] + func clearErrorTraces() +} + +// Default implementation using UserDefaults +class UserDefaultsEventStorage: EventStorage { + private let errorTracesKey = "errorTraces" + + func saveErrorTrace(_ trace: [String]) { + var existingTraces = fetchErrorTraces() + existingTraces.append(trace) + if let encoded = try? JSONEncoder().encode(existingTraces) { + UserDefaults.standard.set(encoded, forKey: errorTracesKey) + } + } + + func fetchErrorTraces() -> [[String]] { + if let data = UserDefaults.standard.data(forKey: errorTracesKey), + let traces = try? JSONDecoder().decode([[String]].self, from: data) { + return traces + } + return [] + } + + func clearErrorTraces() { + UserDefaults.standard.removeObject(forKey: errorTracesKey) + } +} diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift new file mode 100644 index 000000000..16aa4c53a --- /dev/null +++ b/Sources/Events/EventsClient.swift @@ -0,0 +1,48 @@ +import Foundation + +// Protocol for TraceEvent +protocol TraceEvent: CustomStringConvertible { + var description: String { get } +} + +// Protocol for ErrorEvent +protocol ErrorEvent: TraceEvent {} + + +// EventsCollector Class +class EventsCollector { + private var trace: [String] = [] + private var topic: String? + private let storage: EventStorage + + init(storage: EventStorage) { + self.storage = storage + } + + // Function to start trace with topic + func startTrace(topic: String) { + self.topic = topic + self.trace = [] + } + + // Function to save event + func saveEvent(_ event: TraceEvent) { + trace.append(event.description) + if event is ErrorEvent { + saveErrorTrace() + endTrace() + } + } + + // Function to end trace + func endTrace() { + self.topic = nil + self.trace = [] + } + + // Private function to save error trace + private func saveErrorTrace() { + storage.saveErrorTrace(trace) + print("Error trace saved: \(trace)") + } +} diff --git a/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift b/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift new file mode 100644 index 000000000..b5c060324 --- /dev/null +++ b/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift @@ -0,0 +1,30 @@ + +import Foundation + +enum NewPairingExecutionTraceEvents: String, TraceEvent { + case pairingStarted = "pairing_started" + case pairingUriValidationSuccess = "pairing_uri_validation_success" + case pairingUriNotExpired = "pairing_uri_not_expired" + case storeNewPairing = "store_new_pairing" + case subscribingPairingTopic = "subscribing_pairing_topic" + case subscribePairingTopicSuccess = "subscribe_pairing_topic_success" + + var description: String { + return self.rawValue + } +} + +// Enum for TraceErrorEvents +enum TraceErrorEvents: String, ErrorEvent { + case noWssConnection = "no_wss_connection" + case noInternetConnection = "no_internet_connection" + case malformedPairingUri = "malformed_pairing_uri" + case activePairingAlreadyExists = "active_pairing_already_exists" + case subscribePairingTopicFailure = "subscribe_pairing_topic_failure" + case pairingExpired = "pairing_expired" + case proposalExpired = "proposal_expired" + + var description: String { + return self.rawValue + } +} From 802ce62ea94898c7fe24c84d59cd7215968198c1 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 3 Jul 2024 07:33:42 +0200 Subject: [PATCH 02/28] add tests scheme --- .../xcschemes/EventsTests 1.xcscheme | 54 +++++++++++++++++++ .../xcschemes/EventsTests.xcscheme | 54 +++++++++++++++++++ Package.swift | 7 ++- .../Engine/Common/ApproveEngine.swift | 1 + Tests/EventsTests/EventsCollectorTests.swift | 6 +++ 5 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme create mode 100644 Tests/EventsTests/EventsCollectorTests.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme new file mode 100644 index 000000000..7f7753025 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme new file mode 100644 index 000000000..7f7753025 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Package.swift b/Package.swift index 6667cedb9..97e0775cf 100644 --- a/Package.swift +++ b/Package.swift @@ -51,7 +51,7 @@ let package = Package( targets: [ .target( name: "WalletConnectSign", - dependencies: ["WalletConnectPairing", "WalletConnectVerify", "WalletConnectSigner"], + dependencies: ["WalletConnectPairing", "WalletConnectVerify", "WalletConnectSigner", "Events"], path: "Sources/WalletConnectSign", resources: [.process("Resources/PrivacyInfo.xcprivacy")]), .target( @@ -172,7 +172,10 @@ let package = Package( dependencies: ["Commons", "TestingUtils"]), .testTarget( name: "WalletConnectModalTests", - dependencies: ["WalletConnectModal", "TestingUtils"]) + dependencies: ["WalletConnectModal", "TestingUtils"]), + .testTarget( + name: "EventsTests", + dependencies: ["Events"]), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index eabb88d6b..4f3f0b4c4 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -1,5 +1,6 @@ import Foundation import Combine +import Events final class ApproveEngine { enum Errors: Error { diff --git a/Tests/EventsTests/EventsCollectorTests.swift b/Tests/EventsTests/EventsCollectorTests.swift new file mode 100644 index 000000000..3354cfb2d --- /dev/null +++ b/Tests/EventsTests/EventsCollectorTests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +class EventsCollectorTests: XCTestCase { + +} From 79c3c2cfbba74a5e655e682192289c90e48911ca Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 3 Jul 2024 08:20:15 +0200 Subject: [PATCH 03/28] add EventsCollectorTests --- Sources/Events/EventStorage.swift | 30 +++++------ Sources/Events/EventsClient.swift | 53 ++++++++++++++++---- Tests/EventsTests/EventsCollectorTests.swift | 53 ++++++++++++++++++++ 3 files changed, 111 insertions(+), 25 deletions(-) diff --git a/Sources/Events/EventStorage.swift b/Sources/Events/EventStorage.swift index 4622c5dcb..f128ae2e2 100644 --- a/Sources/Events/EventStorage.swift +++ b/Sources/Events/EventStorage.swift @@ -5,32 +5,32 @@ import Foundation // Protocol for EventStorage protocol EventStorage { - func saveErrorTrace(_ trace: [String]) - func fetchErrorTraces() -> [[String]] - func clearErrorTraces() + func saveErrorEvent(_ event: Event) + func fetchErrorEvents() -> [Event] + func clearErrorEvents() } // Default implementation using UserDefaults class UserDefaultsEventStorage: EventStorage { - private let errorTracesKey = "errorTraces" + private let errorEventsKey = "com.walletconnect.sdk.errorEvents" - func saveErrorTrace(_ trace: [String]) { - var existingTraces = fetchErrorTraces() - existingTraces.append(trace) - if let encoded = try? JSONEncoder().encode(existingTraces) { - UserDefaults.standard.set(encoded, forKey: errorTracesKey) + func saveErrorEvent(_ event: Event) { + var existingEvents = fetchErrorEvents() + existingEvents.append(event) + if let encoded = try? JSONEncoder().encode(existingEvents) { + UserDefaults.standard.set(encoded, forKey: errorEventsKey) } } - func fetchErrorTraces() -> [[String]] { - if let data = UserDefaults.standard.data(forKey: errorTracesKey), - let traces = try? JSONDecoder().decode([[String]].self, from: data) { - return traces + func fetchErrorEvents() -> [Event] { + if let data = UserDefaults.standard.data(forKey: errorEventsKey), + let events = try? JSONDecoder().decode([Event].self, from: data) { + return events } return [] } - func clearErrorTraces() { - UserDefaults.standard.removeObject(forKey: errorTracesKey) + func clearErrorEvents() { + UserDefaults.standard.removeObject(forKey: errorEventsKey) } } diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 16aa4c53a..8b2b5fdec 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -9,14 +9,15 @@ protocol TraceEvent: CustomStringConvertible { protocol ErrorEvent: TraceEvent {} -// EventsCollector Class class EventsCollector { - private var trace: [String] = [] - private var topic: String? + var trace: [String] = [] + var topic: String? private let storage: EventStorage + private let bundleId: String - init(storage: EventStorage) { + init(storage: EventStorage, bundleId: String) { self.storage = storage + self.bundleId = bundleId } // Function to start trace with topic @@ -28,8 +29,8 @@ class EventsCollector { // Function to save event func saveEvent(_ event: TraceEvent) { trace.append(event.description) - if event is ErrorEvent { - saveErrorTrace() + if let errorEvent = event as? ErrorEvent { + saveErrorEvent(errorEvent) endTrace() } } @@ -40,9 +41,41 @@ class EventsCollector { self.trace = [] } - // Private function to save error trace - private func saveErrorTrace() { - storage.saveErrorTrace(trace) - print("Error trace saved: \(trace)") + // Private function to save error event + private func saveErrorEvent(_ errorEvent: ErrorEvent) { + let event = Event( + eventId: UUID().uuidString, + bundleId: bundleId, + timestamp: Int64(Date().timeIntervalSince1970 * 1000), + props: Props( + event: "ERROR", + type: errorEvent.description, + properties: Properties( + topic: topic, + trace: trace + ) + ) + ) + storage.saveErrorEvent(event) + print("Error event saved: \(event)") } } + + +#if DEBUG +class MockEventStorage: EventStorage { + private(set) var savedEvents: [Event] = [] + + func saveErrorEvent(_ event: Event) { + savedEvents.append(event) + } + + func fetchErrorEvents() -> [Event] { + return savedEvents + } + + func clearErrorEvents() { + savedEvents.removeAll() + } +} +#endif diff --git a/Tests/EventsTests/EventsCollectorTests.swift b/Tests/EventsTests/EventsCollectorTests.swift index 3354cfb2d..d5b3ccef0 100644 --- a/Tests/EventsTests/EventsCollectorTests.swift +++ b/Tests/EventsTests/EventsCollectorTests.swift @@ -1,6 +1,59 @@ import Foundation import XCTest +@testable import Events class EventsCollectorTests: XCTestCase { + var mockStorage: MockEventStorage! + var eventsCollector: EventsCollector! + + override func setUp() { + super.setUp() + mockStorage = MockEventStorage() + eventsCollector = EventsCollector(storage: mockStorage, bundleId: "com.wallet.example") + } + + override func tearDown() { + eventsCollector = nil + mockStorage = nil + super.tearDown() + } + + func testStartTrace() { + eventsCollector.startTrace(topic: "test_topic") + XCTAssertEqual(eventsCollector.topic, "test_topic") + XCTAssertEqual(eventsCollector.trace.count, 0) + } + + func testSaveEvent() { + eventsCollector.startTrace(topic: "test_topic") + eventsCollector.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) + + XCTAssertEqual(eventsCollector.trace, ["pairing_started"]) + XCTAssertEqual(mockStorage.savedEvents.count, 0) + } + + func testSaveErrorEvent() { + eventsCollector.startTrace(topic: "test_topic") + eventsCollector.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) + eventsCollector.saveEvent(TraceErrorEvents.noInternetConnection) + + XCTAssertEqual(mockStorage.savedEvents.count, 1) + let savedEvent = mockStorage.savedEvents.first + XCTAssertNotNil(savedEvent) + XCTAssertEqual(savedEvent?.props.type, "no_internet_connection") + XCTAssertEqual(savedEvent?.props.properties?.topic, "test_topic") + XCTAssertEqual(savedEvent?.props.properties?.trace, ["pairing_started", "no_internet_connection"]) + XCTAssertNil(eventsCollector.topic) + XCTAssertEqual(eventsCollector.trace.count, 0) + } + + func testEndTrace() { + eventsCollector.startTrace(topic: "test_topic") + eventsCollector.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) + eventsCollector.endTrace() + + XCTAssertNil(eventsCollector.topic) + XCTAssertEqual(eventsCollector.trace.count, 0) + } } From 5302e2e577c271cd2482bcb6ca8a1eefa14de260 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 3 Jul 2024 12:21:10 +0200 Subject: [PATCH 04/28] Add networking --- Sources/Events/Event.swift | 1 - Sources/Events/EventStorage.swift | 23 +++- Sources/Events/EventsClient.swift | 100 ++++++------------ Sources/Events/EventsCollector.swift | 63 +++++++++++ Sources/Events/EventsDispatcher.swift | 39 +++++++ Sources/Events/NetworkingService.swift | 67 ++++++++++++ Tests/EventsTests/EventsCollectorTests.swift | 9 -- Tests/EventsTests/EventsDispatcherTests.swift | 38 +++++++ 8 files changed, 261 insertions(+), 79 deletions(-) create mode 100644 Sources/Events/EventsCollector.swift create mode 100644 Sources/Events/EventsDispatcher.swift create mode 100644 Sources/Events/NetworkingService.swift create mode 100644 Tests/EventsTests/EventsDispatcherTests.swift diff --git a/Sources/Events/Event.swift b/Sources/Events/Event.swift index 29b2f8e13..cc8c4d3c1 100644 --- a/Sources/Events/Event.swift +++ b/Sources/Events/Event.swift @@ -1,6 +1,5 @@ import Foundation - struct Event: Codable { let eventId: String let bundleId: String diff --git a/Sources/Events/EventStorage.swift b/Sources/Events/EventStorage.swift index f128ae2e2..348e5b7c1 100644 --- a/Sources/Events/EventStorage.swift +++ b/Sources/Events/EventStorage.swift @@ -1,9 +1,6 @@ -// import Foundation - -// Protocol for EventStorage protocol EventStorage { func saveErrorEvent(_ event: Event) func fetchErrorEvents() -> [Event] @@ -34,3 +31,23 @@ class UserDefaultsEventStorage: EventStorage { UserDefaults.standard.removeObject(forKey: errorEventsKey) } } + + +#if DEBUG +class MockEventStorage: EventStorage { + private(set) var savedEvents: [Event] = [] + + func saveErrorEvent(_ event: Event) { + savedEvents.append(event) + } + + func fetchErrorEvents() -> [Event] { + return savedEvents + } + + func clearErrorEvents() { + savedEvents.removeAll() + } +} +#endif + diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 8b2b5fdec..ff29c7f3a 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -1,81 +1,49 @@ import Foundation -// Protocol for TraceEvent -protocol TraceEvent: CustomStringConvertible { - var description: String { get } -} - -// Protocol for ErrorEvent -protocol ErrorEvent: TraceEvent {} - - -class EventsCollector { - var trace: [String] = [] - var topic: String? - private let storage: EventStorage - private let bundleId: String - init(storage: EventStorage, bundleId: String) { - self.storage = storage - self.bundleId = bundleId - } - - // Function to start trace with topic - func startTrace(topic: String) { - self.topic = topic - self.trace = [] - } +import Foundation - // Function to save event - func saveEvent(_ event: TraceEvent) { - trace.append(event.description) - if let errorEvent = event as? ErrorEvent { - saveErrorEvent(errorEvent) - endTrace() - } +class EventsClientFactory { + static func createEventsClient(projectId: String, sdkType: String, sdkVersion: String, bundleId: String) -> EventsClient { + let storage = UserDefaultsEventStorage() + let networkingService = NetworkingService(projectId: projectId, sdkType: sdkType, sdkVersion: sdkVersion) + return EventsClient(storage: storage, bundleId: bundleId, networkingService: networkingService) } +} +class EventsClient { + private let eventsCollector: EventsCollector + private let eventsDispatcher: EventsDispatcher - // Function to end trace - func endTrace() { - self.topic = nil - self.trace = [] + init(storage: EventStorage, bundleId: String, networkingService: NetworkingServiceProtocol) { + self.eventsCollector = EventsCollector(storage: storage, bundleId: bundleId) + let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 5, multiplier: 2) + self.eventsDispatcher = EventsDispatcher(networkingService: networkingService, retryPolicy: retryPolicy) + Task { await sendStoredEvents() } } - // Private function to save error event - private func saveErrorEvent(_ errorEvent: ErrorEvent) { - let event = Event( - eventId: UUID().uuidString, - bundleId: bundleId, - timestamp: Int64(Date().timeIntervalSince1970 * 1000), - props: Props( - event: "ERROR", - type: errorEvent.description, - properties: Properties( - topic: topic, - trace: trace - ) - ) - ) - storage.saveErrorEvent(event) - print("Error event saved: \(event)") + // Public method to start trace + public func startTrace(topic: String) { + eventsCollector.startTrace(topic: topic) } -} - -#if DEBUG -class MockEventStorage: EventStorage { - private(set) var savedEvents: [Event] = [] - - func saveErrorEvent(_ event: Event) { - savedEvents.append(event) + // Public method to save event + public func saveEvent(_ event: TraceEvent) { + eventsCollector.saveEvent(event) } - func fetchErrorEvents() -> [Event] { - return savedEvents - } + // Public method to send stored events + private func sendStoredEvents() async { + let events = eventsCollector.storage.fetchErrorEvents() + guard !events.isEmpty else { return } - func clearErrorEvents() { - savedEvents.removeAll() + do { + let success: Bool = try await eventsDispatcher.executeWithRetry(events: events) + if success { + self.eventsCollector.storage.clearErrorEvents() + } + } catch { + print("Failed to send events after multiple attempts: \(error)") + } } } -#endif + diff --git a/Sources/Events/EventsCollector.swift b/Sources/Events/EventsCollector.swift new file mode 100644 index 000000000..a8a6cbeb6 --- /dev/null +++ b/Sources/Events/EventsCollector.swift @@ -0,0 +1,63 @@ +import Foundation + +// Protocol for TraceEvent +protocol TraceEvent: CustomStringConvertible { + var description: String { get } +} + +// Protocol for ErrorEvent +protocol ErrorEvent: TraceEvent {} + + +class EventsCollector { + var trace: [String] = [] + var topic: String? + let storage: EventStorage + private let bundleId: String + + init(storage: EventStorage, bundleId: String) { + self.storage = storage + self.bundleId = bundleId + } + + // Function to start trace with topic + func startTrace(topic: String) { + self.topic = topic + self.trace = [] + } + + // Function to save event + func saveEvent(_ event: TraceEvent) { + trace.append(event.description) + if let errorEvent = event as? ErrorEvent { + saveErrorEvent(errorEvent) + endTrace() + } + } + + // Function to end trace + private func endTrace() { + self.topic = nil + self.trace = [] + } + + // Private function to save error event + private func saveErrorEvent(_ errorEvent: ErrorEvent) { + let event = Event( + eventId: UUID().uuidString, + bundleId: bundleId, + timestamp: Int64(Date().timeIntervalSince1970 * 1000), + props: Props( + event: "ERROR", + type: errorEvent.description, + properties: Properties( + topic: topic, + trace: trace + ) + ) + ) + storage.saveErrorEvent(event) + print("Error event saved: \(event)") + } +} + diff --git a/Sources/Events/EventsDispatcher.swift b/Sources/Events/EventsDispatcher.swift new file mode 100644 index 000000000..4df0eaee7 --- /dev/null +++ b/Sources/Events/EventsDispatcher.swift @@ -0,0 +1,39 @@ + +import Foundation + +struct RetryPolicy { + let maxAttempts: Int + let initialDelay: TimeInterval + let multiplier: Double + var delayOverride: TimeInterval? = nil +} + +class EventsDispatcher { + private let networkingService: NetworkingServiceProtocol + private let retryPolicy: RetryPolicy + + init(networkingService: NetworkingServiceProtocol, retryPolicy: RetryPolicy) { + self.networkingService = networkingService + self.retryPolicy = retryPolicy + } + + func executeWithRetry(events: [Event]) async throws -> Bool { + var attempts = 0 + var delay = retryPolicy.initialDelay + + while attempts < retryPolicy.maxAttempts { + attempts += 1 + do { + return try await networkingService.sendEvents(events) + } catch { + if attempts >= retryPolicy.maxAttempts { + throw error + } + let actualDelay = retryPolicy.delayOverride ?? delay + try await Task.sleep(nanoseconds: UInt64(actualDelay * Double(NSEC_PER_SEC))) + delay *= retryPolicy.multiplier + } + } + throw NSError(domain: "EventsDispatcherError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Max retry attempts reached"]) + } +} diff --git a/Sources/Events/NetworkingService.swift b/Sources/Events/NetworkingService.swift new file mode 100644 index 000000000..8f7b647c1 --- /dev/null +++ b/Sources/Events/NetworkingService.swift @@ -0,0 +1,67 @@ + +import Foundation + +protocol NetworkingServiceProtocol { + func sendEvents(_ events: [Event]) async throws -> Bool +} + + +class NetworkingService: NetworkingServiceProtocol { + private let session: URLSession + private let projectId: String + private let sdkType: String + private let sdkVersion: String + private let apiURL = URL(string: "https://pulse.walletconnect.com/batch")! + + init(session: URLSession = .shared, projectId: String, sdkType: String, sdkVersion: String) { + self.session = session + self.projectId = projectId + self.sdkType = sdkType + self.sdkVersion = sdkVersion + } + + func sendEvents(_ events: [Event]) async throws -> Bool { + var request = URLRequest(url: apiURL) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.setValue(projectId, forHTTPHeaderField: "x-project-id") + request.setValue(sdkType, forHTTPHeaderField: "x-sdk-type") + request.setValue(sdkVersion, forHTTPHeaderField: "x-sdk-version") + + request.httpBody = try JSONEncoder().encode(events) + + return try await withCheckedThrowingContinuation { continuation in + let task = session.dataTask(with: request) { data, response, error in + if let error = error { + continuation.resume(throwing: error) + return + } + + guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + continuation.resume(returning: false) + return + } + + continuation.resume(returning: true) + } + + task.priority = URLSessionTask.lowPriority + task.resume() + } + } +} + +#if DEBUG +class MockNetworkingService: NetworkingServiceProtocol { + var shouldFail = false + var attemptCount = 0 + + func sendEvents(_ events: [Event]) async throws -> Bool { + attemptCount += 1 + if shouldFail { + throw NSError(domain: "MockError", code: -1, userInfo: nil) + } + return true + } +} +#endif diff --git a/Tests/EventsTests/EventsCollectorTests.swift b/Tests/EventsTests/EventsCollectorTests.swift index d5b3ccef0..2379c500a 100644 --- a/Tests/EventsTests/EventsCollectorTests.swift +++ b/Tests/EventsTests/EventsCollectorTests.swift @@ -47,13 +47,4 @@ class EventsCollectorTests: XCTestCase { XCTAssertNil(eventsCollector.topic) XCTAssertEqual(eventsCollector.trace.count, 0) } - - func testEndTrace() { - eventsCollector.startTrace(topic: "test_topic") - eventsCollector.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) - eventsCollector.endTrace() - - XCTAssertNil(eventsCollector.topic) - XCTAssertEqual(eventsCollector.trace.count, 0) - } } diff --git a/Tests/EventsTests/EventsDispatcherTests.swift b/Tests/EventsTests/EventsDispatcherTests.swift new file mode 100644 index 000000000..e7b980e5a --- /dev/null +++ b/Tests/EventsTests/EventsDispatcherTests.swift @@ -0,0 +1,38 @@ +import XCTest +@testable import Events + +class EventsDispatcherTests: XCTestCase { + var mockNetworkingService: MockNetworkingService! + var eventsDispatcher: EventsDispatcher! + let events = [Event(eventId: UUID().uuidString, bundleId: "com.wallet.example", timestamp: Int64(Date().timeIntervalSince1970 * 1000), props: Props(event: "ERROR", type: "test_error", properties: Properties(topic: "test_topic", trace: ["test_trace"])))] + + override func setUp() { + super.setUp() + mockNetworkingService = MockNetworkingService() + let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 1, multiplier: 1.5, delayOverride: 0.001) + eventsDispatcher = EventsDispatcher(networkingService: mockNetworkingService, retryPolicy: retryPolicy) + } + + override func tearDown() { + eventsDispatcher = nil + mockNetworkingService = nil + super.tearDown() + } + + func testRetrySuccess() async throws { + mockNetworkingService.shouldFail = true + do { + _ = try await eventsDispatcher.executeWithRetry(events: events) + XCTFail("Expected to throw an error") + } catch { + XCTAssertEqual(mockNetworkingService.attemptCount, 3) + } + } + + func testRetryFailure() async throws { + mockNetworkingService.shouldFail = false + let result = try await eventsDispatcher.executeWithRetry(events: events) + XCTAssertEqual(result, true) + XCTAssertEqual(mockNetworkingService.attemptCount, 1) + } +} From 9a5a08eed69a6a6cecebd5c9a9fd60b37cd732fa Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 3 Jul 2024 12:26:57 +0200 Subject: [PATCH 05/28] savepoint --- Sources/Events/EventsClient.swift | 9 --------- Sources/Events/EventsClientFactory.swift | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 Sources/Events/EventsClientFactory.swift diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index ff29c7f3a..4a05fa9cf 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -1,15 +1,6 @@ import Foundation -import Foundation - -class EventsClientFactory { - static func createEventsClient(projectId: String, sdkType: String, sdkVersion: String, bundleId: String) -> EventsClient { - let storage = UserDefaultsEventStorage() - let networkingService = NetworkingService(projectId: projectId, sdkType: sdkType, sdkVersion: sdkVersion) - return EventsClient(storage: storage, bundleId: bundleId, networkingService: networkingService) - } -} class EventsClient { private let eventsCollector: EventsCollector private let eventsDispatcher: EventsDispatcher diff --git a/Sources/Events/EventsClientFactory.swift b/Sources/Events/EventsClientFactory.swift new file mode 100644 index 000000000..f69c727cc --- /dev/null +++ b/Sources/Events/EventsClientFactory.swift @@ -0,0 +1,10 @@ + +import Foundation + +class EventsClientFactory { + static func createEventsClient(projectId: String, sdkType: String, sdkVersion: String, bundleId: String) -> EventsClient { + let storage = UserDefaultsEventStorage() + let networkingService = NetworkingService(projectId: projectId, sdkType: sdkType, sdkVersion: sdkVersion) + return EventsClient(storage: storage, bundleId: bundleId, networkingService: networkingService) + } +} From 8d00c136d5316f95ec9caaad80f9834b542ce07e Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 4 Jul 2024 09:37:09 +0200 Subject: [PATCH 06/28] savepoint --- Example/DApp/SceneDelegate.swift | 9 +++++++ Package.swift | 2 +- Sources/Events/EventsClient.swift | 21 +++++++++------- Sources/Events/EventsClientFactory.swift | 24 +++++++++++++++---- Sources/Events/EventsCollector.swift | 10 ++++++-- Sources/Events/EventsImports.swift | 3 +++ .../Auth/Link/LinkAuthRequester.swift | 1 - 7 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 Sources/Events/EventsImports.swift diff --git a/Example/DApp/SceneDelegate.swift b/Example/DApp/SceneDelegate.swift index 2153d26f3..5d5c3cb62 100644 --- a/Example/DApp/SceneDelegate.swift +++ b/Example/DApp/SceneDelegate.swift @@ -117,6 +117,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { order: 1, mobileLink: "walletapp://", linkMode: "https://lab.web3modal.com/wallet" + ), + .init( + id: "rn-sample", + name: "RN Sample Wallet", + homepage: "https://walletconnect.com/", + imageUrl: "https://avatars.githubusercontent.com/u/37784886?s=200&v=4", + order: 1, + mobileLink: "rn-web3wallet://", + linkMode: "https://lab.web3modal.com/walletkit_rn" ) ] ) diff --git a/Package.swift b/Package.swift index 97e0775cf..2b1a5f766 100644 --- a/Package.swift +++ b/Package.swift @@ -128,7 +128,7 @@ let package = Package( dependencies: ["WalletConnectUtils"]), .target( name: "Events", - dependencies: []), + dependencies: ["WalletConnectUtils"]), .target( name: "WalletConnectModal", dependencies: ["QRCode", "WalletConnectSign"], diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 4a05fa9cf..854923a05 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -1,14 +1,18 @@ import Foundation - class EventsClient { private let eventsCollector: EventsCollector private let eventsDispatcher: EventsDispatcher - - init(storage: EventStorage, bundleId: String, networkingService: NetworkingServiceProtocol) { - self.eventsCollector = EventsCollector(storage: storage, bundleId: bundleId) - let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 5, multiplier: 2) - self.eventsDispatcher = EventsDispatcher(networkingService: networkingService, retryPolicy: retryPolicy) + private let logger: ConsoleLogging + + init( + eventsCollector: EventsCollector, + eventsDispatcher: EventsDispatcher, + logger: ConsoleLogging + ) { + self.eventsCollector = eventsCollector + self.eventsDispatcher = eventsDispatcher + self.logger = logger Task { await sendStoredEvents() } } @@ -23,7 +27,7 @@ class EventsClient { } // Public method to send stored events - private func sendStoredEvents() async { + public func sendStoredEvents() async { let events = eventsCollector.storage.fetchErrorEvents() guard !events.isEmpty else { return } @@ -33,8 +37,7 @@ class EventsClient { self.eventsCollector.storage.clearErrorEvents() } } catch { - print("Failed to send events after multiple attempts: \(error)") + logger.debug("Failed to send events after multiple attempts: \(error)") } } } - diff --git a/Sources/Events/EventsClientFactory.swift b/Sources/Events/EventsClientFactory.swift index f69c727cc..5b1489b69 100644 --- a/Sources/Events/EventsClientFactory.swift +++ b/Sources/Events/EventsClientFactory.swift @@ -1,10 +1,26 @@ - import Foundation class EventsClientFactory { - static func createEventsClient(projectId: String, sdkType: String, sdkVersion: String, bundleId: String) -> EventsClient { + static func createEventsClient( + projectId: String, + sdkType: String, + sdkVersion: String, + bundleId: String + ) -> EventsClient { let storage = UserDefaultsEventStorage() - let networkingService = NetworkingService(projectId: projectId, sdkType: sdkType, sdkVersion: sdkVersion) - return EventsClient(storage: storage, bundleId: bundleId, networkingService: networkingService) + let networkingService = NetworkingService( + projectId: projectId, + sdkType: sdkType, + sdkVersion: sdkVersion + ) + let logger = ConsoleLogger(prefix: "", loggingLevel: .off) + let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 5, multiplier: 2) + let eventsDispatcher = EventsDispatcher(networkingService: networkingService, retryPolicy: retryPolicy) + let eventsCollector = EventsCollector(storage: storage, bundleId: bundleId, logger: logger) + return EventsClient( + eventsCollector: eventsCollector, + eventsDispatcher: eventsDispatcher, + logger: logger + ) } } diff --git a/Sources/Events/EventsCollector.swift b/Sources/Events/EventsCollector.swift index a8a6cbeb6..8fa213441 100644 --- a/Sources/Events/EventsCollector.swift +++ b/Sources/Events/EventsCollector.swift @@ -13,11 +13,17 @@ class EventsCollector { var trace: [String] = [] var topic: String? let storage: EventStorage + private let logger: ConsoleLogging private let bundleId: String - init(storage: EventStorage, bundleId: String) { + init( + storage: EventStorage, + bundleId: String, + logger: ConsoleLogging + ) { self.storage = storage self.bundleId = bundleId + self.logger = logger } // Function to start trace with topic @@ -57,7 +63,7 @@ class EventsCollector { ) ) storage.saveErrorEvent(event) - print("Error event saved: \(event)") + logger.debug("Error event saved: \(event)") } } diff --git a/Sources/Events/EventsImports.swift b/Sources/Events/EventsImports.swift new file mode 100644 index 000000000..39a0c89b7 --- /dev/null +++ b/Sources/Events/EventsImports.swift @@ -0,0 +1,3 @@ +#if !CocoaPods +@_exported import WalletConnectUtils +#endif diff --git a/Sources/WalletConnectSign/Auth/Link/LinkAuthRequester.swift b/Sources/WalletConnectSign/Auth/Link/LinkAuthRequester.swift index c18b9fb78..228baef25 100644 --- a/Sources/WalletConnectSign/Auth/Link/LinkAuthRequester.swift +++ b/Sources/WalletConnectSign/Auth/Link/LinkAuthRequester.swift @@ -31,7 +31,6 @@ actor LinkAuthRequester { } func request(params: AuthRequestParams, walletUniversalLink: String) async throws -> String { - guard try linkModeLinksStore.get(key: walletUniversalLink) != nil else { throw Errors.walletLinkSupportNotProven } var params = params From 19c18262f99dae609c1fb7cf8796039ed9294dc3 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 4 Jul 2024 09:51:08 +0200 Subject: [PATCH 07/28] upgrade on link mode auth response --- Example/DApp/SceneDelegate.swift | 9 +++++++++ .../Auth/Services/App/AuthResponseSubscriber.swift | 2 ++ 2 files changed, 11 insertions(+) diff --git a/Example/DApp/SceneDelegate.swift b/Example/DApp/SceneDelegate.swift index 2153d26f3..5d5c3cb62 100644 --- a/Example/DApp/SceneDelegate.swift +++ b/Example/DApp/SceneDelegate.swift @@ -117,6 +117,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { order: 1, mobileLink: "walletapp://", linkMode: "https://lab.web3modal.com/wallet" + ), + .init( + id: "rn-sample", + name: "RN Sample Wallet", + homepage: "https://walletconnect.com/", + imageUrl: "https://avatars.githubusercontent.com/u/37784886?s=200&v=4", + order: 1, + mobileLink: "rn-web3wallet://", + linkMode: "https://lab.web3modal.com/walletkit_rn" ) ] ) diff --git a/Sources/WalletConnectSign/Auth/Services/App/AuthResponseSubscriber.swift b/Sources/WalletConnectSign/Auth/Services/App/AuthResponseSubscriber.swift index 578b6a75e..03f0456be 100644 --- a/Sources/WalletConnectSign/Auth/Services/App/AuthResponseSubscriber.swift +++ b/Sources/WalletConnectSign/Auth/Services/App/AuthResponseSubscriber.swift @@ -97,6 +97,8 @@ class AuthResponseSubscriber { linkEnvelopesDispatcher.responseSubscription(on: SessionAuthenticatedProtocolMethod.responseApprove()) .sink { [unowned self] (payload: ResponseSubscriptionPayload) in + _ = getTransportTypeUpgradeIfPossible(peerMetadata: payload.response.responder.metadata, requestId: payload.id) + let pairingTopic = payload.topic pairingRegisterer.activate(pairingTopic: pairingTopic, peerMetadata: nil) removeResponseTopicRecord(responseTopic: payload.topic) From 5d1ca6fa75f70216df003cd368f89228674c1a86 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 4 Jul 2024 11:55:51 +0200 Subject: [PATCH 08/28] build apps with events package --- Package.swift | 4 ++-- Sources/Events/Events.swift | 11 +++++++++++ Sources/Events/EventsClient.swift | 2 +- Sources/Events/EventsClientFactory.swift | 12 +++++------- Sources/Events/EventsCollector.swift | 6 ++---- Sources/Events/EventsImports.swift | 2 ++ Sources/Events/NetworkingService.swift | 6 ++---- Sources/WalletConnectPairing/Pair.swift | 6 +++++- .../WalletConnectPairing/PairingClientFactory.swift | 8 +++++--- Sources/WalletConnectPairing/PairingImports.swift | 1 + .../Services/Wallet/WalletPairService.swift | 5 ++++- Sources/WalletConnectSign/Sign/SignImports.swift | 2 ++ 12 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 Sources/Events/Events.swift diff --git a/Package.swift b/Package.swift index 2b1a5f766..7e5c3133c 100644 --- a/Package.swift +++ b/Package.swift @@ -84,7 +84,7 @@ let package = Package( path: "Sources/WalletConnectKMS"), .target( name: "WalletConnectPairing", - dependencies: ["WalletConnectNetworking"], + dependencies: ["WalletConnectNetworking", "Events"], resources: [.process("Resources/PrivacyInfo.xcprivacy")]), .target( name: "WalletConnectSigner", @@ -128,7 +128,7 @@ let package = Package( dependencies: ["WalletConnectUtils"]), .target( name: "Events", - dependencies: ["WalletConnectUtils"]), + dependencies: ["WalletConnectUtils", "WalletConnectNetworking"]), .target( name: "WalletConnectModal", dependencies: ["QRCode", "WalletConnectSign"], diff --git a/Sources/Events/Events.swift b/Sources/Events/Events.swift new file mode 100644 index 000000000..5b9d3e57a --- /dev/null +++ b/Sources/Events/Events.swift @@ -0,0 +1,11 @@ +import Foundation + +public class Events { + /// Singleton instance of EventsClient + public static var instance: EventsClient = { + return EventsClientFactory.create( + projectId: Networking.projectId, + sdkVersion: EnvironmentInfo.sdkName + ) + }() +} diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 854923a05..6a2a4cd5f 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -1,6 +1,6 @@ import Foundation -class EventsClient { +public class EventsClient { private let eventsCollector: EventsCollector private let eventsDispatcher: EventsDispatcher private let logger: ConsoleLogging diff --git a/Sources/Events/EventsClientFactory.swift b/Sources/Events/EventsClientFactory.swift index 5b1489b69..e8384eac2 100644 --- a/Sources/Events/EventsClientFactory.swift +++ b/Sources/Events/EventsClientFactory.swift @@ -1,22 +1,19 @@ import Foundation -class EventsClientFactory { - static func createEventsClient( +public class EventsClientFactory { + static func create( projectId: String, - sdkType: String, sdkVersion: String, - bundleId: String + storage: EventStorage = UserDefaultsEventStorage() ) -> EventsClient { - let storage = UserDefaultsEventStorage() let networkingService = NetworkingService( projectId: projectId, - sdkType: sdkType, sdkVersion: sdkVersion ) let logger = ConsoleLogger(prefix: "", loggingLevel: .off) let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 5, multiplier: 2) let eventsDispatcher = EventsDispatcher(networkingService: networkingService, retryPolicy: retryPolicy) - let eventsCollector = EventsCollector(storage: storage, bundleId: bundleId, logger: logger) + let eventsCollector = EventsCollector(storage: storage, logger: logger) return EventsClient( eventsCollector: eventsCollector, eventsDispatcher: eventsDispatcher, @@ -24,3 +21,4 @@ class EventsClientFactory { ) } } + diff --git a/Sources/Events/EventsCollector.swift b/Sources/Events/EventsCollector.swift index 8fa213441..09f255dbd 100644 --- a/Sources/Events/EventsCollector.swift +++ b/Sources/Events/EventsCollector.swift @@ -1,7 +1,7 @@ import Foundation // Protocol for TraceEvent -protocol TraceEvent: CustomStringConvertible { +public protocol TraceEvent: CustomStringConvertible { var description: String { get } } @@ -14,15 +14,12 @@ class EventsCollector { var topic: String? let storage: EventStorage private let logger: ConsoleLogging - private let bundleId: String init( storage: EventStorage, - bundleId: String, logger: ConsoleLogging ) { self.storage = storage - self.bundleId = bundleId self.logger = logger } @@ -49,6 +46,7 @@ class EventsCollector { // Private function to save error event private func saveErrorEvent(_ errorEvent: ErrorEvent) { + let bundleId = Bundle.main.bundleIdentifier ?? "Unknown" let event = Event( eventId: UUID().uuidString, bundleId: bundleId, diff --git a/Sources/Events/EventsImports.swift b/Sources/Events/EventsImports.swift index 39a0c89b7..5e63a68cb 100644 --- a/Sources/Events/EventsImports.swift +++ b/Sources/Events/EventsImports.swift @@ -1,3 +1,5 @@ #if !CocoaPods @_exported import WalletConnectUtils +@_exported import WalletConnectNetworking +@_exported import WalletConnectRelay #endif diff --git a/Sources/Events/NetworkingService.swift b/Sources/Events/NetworkingService.swift index 8f7b647c1..76754849d 100644 --- a/Sources/Events/NetworkingService.swift +++ b/Sources/Events/NetworkingService.swift @@ -9,14 +9,12 @@ protocol NetworkingServiceProtocol { class NetworkingService: NetworkingServiceProtocol { private let session: URLSession private let projectId: String - private let sdkType: String private let sdkVersion: String private let apiURL = URL(string: "https://pulse.walletconnect.com/batch")! - init(session: URLSession = .shared, projectId: String, sdkType: String, sdkVersion: String) { + init(session: URLSession = .shared, projectId: String, sdkVersion: String) { self.session = session self.projectId = projectId - self.sdkType = sdkType self.sdkVersion = sdkVersion } @@ -25,7 +23,7 @@ class NetworkingService: NetworkingServiceProtocol { request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue(projectId, forHTTPHeaderField: "x-project-id") - request.setValue(sdkType, forHTTPHeaderField: "x-sdk-type") + request.setValue("events_sdk", forHTTPHeaderField: "x-sdk-type") request.setValue(sdkVersion, forHTTPHeaderField: "x-sdk-version") request.httpBody = try JSONEncoder().encode(events) diff --git a/Sources/WalletConnectPairing/Pair.swift b/Sources/WalletConnectPairing/Pair.swift index 08eafec7e..8924420cd 100644 --- a/Sources/WalletConnectPairing/Pair.swift +++ b/Sources/WalletConnectPairing/Pair.swift @@ -37,6 +37,10 @@ private extension Pair { guard let config = Pair.config else { fatalError("Error - you must call Pair.configure(_:) before accessing the shared instance.") } - return PairingClientFactory.create(networkingClient: Networking.interactor, groupIdentifier: Networking.groupIdentifier) + return PairingClientFactory.create( + networkingClient: Networking.interactor, + eventsClient: Events.instance, + groupIdentifier: Networking.groupIdentifier + ) }() } diff --git a/Sources/WalletConnectPairing/PairingClientFactory.swift b/Sources/WalletConnectPairing/PairingClientFactory.swift index 22840bed3..18f609b39 100644 --- a/Sources/WalletConnectPairing/PairingClientFactory.swift +++ b/Sources/WalletConnectPairing/PairingClientFactory.swift @@ -4,6 +4,7 @@ public struct PairingClientFactory { public static func create( networkingClient: NetworkingInteractor, + eventsClient: EventsClient, groupIdentifier: String ) -> PairingClient { let logger = ConsoleLogger(loggingLevel: .off) @@ -13,20 +14,21 @@ public struct PairingClientFactory { } let keychainStorage = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk", accessGroup: groupIdentifier) - return PairingClientFactory.create(logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychainStorage, networkingClient: networkingClient) + return PairingClientFactory.create(logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychainStorage, networkingClient: networkingClient, eventsClient: eventsClient) } public static func create( logger: ConsoleLogging, keyValueStorage: KeyValueStorage, keychainStorage: KeychainStorageProtocol, - networkingClient: NetworkingInteractor + networkingClient: NetworkingInteractor, + eventsClient: EventsClient ) -> PairingClient { let pairingStore = PairingStorage(storage: SequenceStore(store: .init(defaults: keyValueStorage, identifier: PairStorageIdentifiers.pairings.rawValue))) let kms = KeyManagementService(keychain: keychainStorage) let history = RPCHistoryFactory.createForNetwork(keyValueStorage: keyValueStorage) let appPairService = AppPairService(networkingInteractor: networkingClient, kms: kms, pairingStorage: pairingStore) - let walletPairService = WalletPairService(networkingInteractor: networkingClient, kms: kms, pairingStorage: pairingStore, history: history, logger: logger) + let walletPairService = WalletPairService(networkingInteractor: networkingClient, kms: kms, pairingStorage: pairingStore, history: history, logger: logger, eventsClient: eventsClient) let pairingRequestsSubscriber = PairingRequestsSubscriber(networkingInteractor: networkingClient, pairingStorage: pairingStore, logger: logger) let pairingsProvider = PairingsProvider(pairingStorage: pairingStore) let cleanupService = PairingCleanupService(pairingStore: pairingStore, kms: kms) diff --git a/Sources/WalletConnectPairing/PairingImports.swift b/Sources/WalletConnectPairing/PairingImports.swift index 23c1738ef..98b75f8a5 100644 --- a/Sources/WalletConnectPairing/PairingImports.swift +++ b/Sources/WalletConnectPairing/PairingImports.swift @@ -1,3 +1,4 @@ #if !CocoaPods @_exported import WalletConnectNetworking +@_exported import Events #endif diff --git a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift index 2592d010d..4fd09290a 100644 --- a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift +++ b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift @@ -8,6 +8,7 @@ actor WalletPairService { let networkingInteractor: NetworkInteracting let kms: KeyManagementServiceProtocol + private let eventsClient: EventsClient private let pairingStorage: WCPairingStorage private let history: RPCHistory private let logger: ConsoleLogging @@ -17,13 +18,15 @@ actor WalletPairService { kms: KeyManagementServiceProtocol, pairingStorage: WCPairingStorage, history: RPCHistory, - logger: ConsoleLogging + logger: ConsoleLogging, + eventsClient: EventsClient ) { self.networkingInteractor = networkingInteractor self.kms = kms self.pairingStorage = pairingStorage self.history = history self.logger = logger + self.eventsClient = eventsClient } func pair(_ uri: WalletConnectURI) async throws { diff --git a/Sources/WalletConnectSign/Sign/SignImports.swift b/Sources/WalletConnectSign/Sign/SignImports.swift index 91463cad3..898b4f971 100644 --- a/Sources/WalletConnectSign/Sign/SignImports.swift +++ b/Sources/WalletConnectSign/Sign/SignImports.swift @@ -2,4 +2,6 @@ @_exported import WalletConnectPairing @_exported import WalletConnectSigner @_exported import WalletConnectVerify +@_exported import WalletConnectRelay +@_exported import Events #endif From abb77a14aa55f8b25e67fd7f9b293e88839c94df Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Jul 2024 10:21:46 +0200 Subject: [PATCH 09/28] savepoint --- .../Pairing/PairingTests.swift | 3 +- .../Sign/SignClientTests.swift | 3 +- .../Web3Wallet/XPlatformW3WTests.swift | 3 +- Sources/Events/EventsClient.swift | 30 ++++++++++++++++++- .../NewPairingExecutionTraceEvents.swift | 8 ++--- .../PairingClientFactory.swift | 2 +- .../Services/Wallet/WalletPairService.swift | 19 +++++++++--- 7 files changed, 55 insertions(+), 13 deletions(-) diff --git a/Example/IntegrationTests/Pairing/PairingTests.swift b/Example/IntegrationTests/Pairing/PairingTests.swift index 2ea13ae0e..80c9e5f0a 100644 --- a/Example/IntegrationTests/Pairing/PairingTests.swift +++ b/Example/IntegrationTests/Pairing/PairingTests.swift @@ -42,7 +42,8 @@ final class PairingTests: XCTestCase { logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychain, - networkingClient: networkingClient) + networkingClient: networkingClient, + eventsClient: MockEventsClient()) return pairingClient diff --git a/Example/IntegrationTests/Sign/SignClientTests.swift b/Example/IntegrationTests/Sign/SignClientTests.swift index 56262453f..04c18cc58 100644 --- a/Example/IntegrationTests/Sign/SignClientTests.swift +++ b/Example/IntegrationTests/Sign/SignClientTests.swift @@ -48,7 +48,8 @@ final class SignClientTests: XCTestCase { logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychain, - networkingClient: networkingClient + networkingClient: networkingClient, + eventsClient: MockEventsClient() ) let metadata = AppMetadata(name: name, description: "", url: "", icons: [""], redirect: try! AppMetadata.Redirect(native: "", universal: linkModeUniversalLink, linkMode: supportLinkMode)) diff --git a/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift b/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift index 8420a3a64..b01538240 100644 --- a/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift +++ b/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift @@ -46,7 +46,8 @@ final class XPlatformW3WTests: XCTestCase { logger: pairingLogger, keyValueStorage: keyValueStorage, keychainStorage: keychain, - networkingClient: networkingClient) + networkingClient: networkingClient, + eventsClient: MockEventsClient()) let signClient = SignClientFactory.create( metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: try! AppMetadata.Redirect(native: "", universal: nil)), diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 6a2a4cd5f..1fc63bce3 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -1,6 +1,12 @@ import Foundation -public class EventsClient { +public protocol EventsClientProtocol { + func startTrace(topic: String) + func saveEvent(_ event: TraceEvent) + func sendStoredEvents() async +} + +public class EventsClient: EventsClientProtocol { private let eventsCollector: EventsCollector private let eventsDispatcher: EventsDispatcher private let logger: ConsoleLogging @@ -41,3 +47,25 @@ public class EventsClient { } } } + +#if DEBUG +public class MockEventsClient: EventsClientProtocol { + var startTraceCalled = false + var saveEventCalled = false + var sendStoredEventsCalled = false + + public init() {} + + public func startTrace(topic: String) { + startTraceCalled = true + } + + public func saveEvent(_ event: TraceEvent) { + saveEventCalled = true + } + + public func sendStoredEvents() async { + sendStoredEventsCalled = true + } +} +#endif diff --git a/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift b/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift index b5c060324..bc4d2ba79 100644 --- a/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift +++ b/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift @@ -1,7 +1,7 @@ import Foundation -enum NewPairingExecutionTraceEvents: String, TraceEvent { +public enum NewPairingExecutionTraceEvents: String, TraceEvent { case pairingStarted = "pairing_started" case pairingUriValidationSuccess = "pairing_uri_validation_success" case pairingUriNotExpired = "pairing_uri_not_expired" @@ -9,13 +9,13 @@ enum NewPairingExecutionTraceEvents: String, TraceEvent { case subscribingPairingTopic = "subscribing_pairing_topic" case subscribePairingTopicSuccess = "subscribe_pairing_topic_success" - var description: String { + public var description: String { return self.rawValue } } // Enum for TraceErrorEvents -enum TraceErrorEvents: String, ErrorEvent { +public enum TraceErrorEvents: String, ErrorEvent { case noWssConnection = "no_wss_connection" case noInternetConnection = "no_internet_connection" case malformedPairingUri = "malformed_pairing_uri" @@ -24,7 +24,7 @@ enum TraceErrorEvents: String, ErrorEvent { case pairingExpired = "pairing_expired" case proposalExpired = "proposal_expired" - var description: String { + public var description: String { return self.rawValue } } diff --git a/Sources/WalletConnectPairing/PairingClientFactory.swift b/Sources/WalletConnectPairing/PairingClientFactory.swift index 18f609b39..26293c3ad 100644 --- a/Sources/WalletConnectPairing/PairingClientFactory.swift +++ b/Sources/WalletConnectPairing/PairingClientFactory.swift @@ -22,7 +22,7 @@ public struct PairingClientFactory { keyValueStorage: KeyValueStorage, keychainStorage: KeychainStorageProtocol, networkingClient: NetworkingInteractor, - eventsClient: EventsClient + eventsClient: EventsClientProtocol ) -> PairingClient { let pairingStore = PairingStorage(storage: SequenceStore(store: .init(defaults: keyValueStorage, identifier: PairStorageIdentifiers.pairings.rawValue))) let kms = KeyManagementService(keychain: keychainStorage) diff --git a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift index 4fd09290a..e7ccd715e 100644 --- a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift +++ b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift @@ -8,7 +8,7 @@ actor WalletPairService { let networkingInteractor: NetworkInteracting let kms: KeyManagementServiceProtocol - private let eventsClient: EventsClient + private let eventsClient: EventsClientProtocol private let pairingStorage: WCPairingStorage private let history: RPCHistory private let logger: ConsoleLogging @@ -19,7 +19,7 @@ actor WalletPairService { pairingStorage: WCPairingStorage, history: RPCHistory, logger: ConsoleLogging, - eventsClient: EventsClient + eventsClient: EventsClientProtocol ) { self.networkingInteractor = networkingInteractor self.kms = kms @@ -30,6 +30,8 @@ actor WalletPairService { } func pair(_ uri: WalletConnectURI) async throws { + eventsClient.startTrace(topic: uri.topic) + eventsClient.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) logger.debug("Pairing with uri: \(uri)") guard try !pairingHasPendingRequest(for: uri.topic) else { logger.debug("Pairing with topic (\(uri.topic)) has pending request") @@ -40,14 +42,22 @@ actor WalletPairService { let symKey = try SymmetricKey(hex: uri.symKey) try kms.setSymmetricKey(symKey, for: pairing.topic) pairingStorage.setPairing(pairing) - + eventsClient.saveEvent(NewPairingExecutionTraceEvents.storeNewPairing) + let networkConnectionStatus = await resolveNetworkConnectionStatus() guard networkConnectionStatus == .connected else { logger.debug("Pairing failed - Network is not connected") + eventsClient.saveEvent(TraceErrorEvents.noInternetConnection) throw Errors.networkNotConnected } - try await networkingInteractor.subscribe(topic: pairing.topic) + do { + try await networkingInteractor.subscribe(topic: pairing.topic) + } catch { + logger.debug("Failed to subscribe to topic: \(pairing.topic)") + eventsClient.saveEvent(TraceErrorEvents.subscribePairingTopicFailure) + throw error + } } } @@ -59,6 +69,7 @@ extension WalletPairService { } if pairing.active { + eventsClient.saveEvent(TraceErrorEvents.activePairingAlreadyExists) throw Errors.pairingAlreadyExist(topic: topic) } From 6d8b3d74ca6ead15682652f636ed655e826f56db Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Jul 2024 12:39:35 +0200 Subject: [PATCH 10/28] savepoint --- ...ents.swift => PairingExecutionTraceEvents.swift} | 9 +++++---- .../NetworkInteracting.swift | 1 + .../NetworkingInteractor.swift | 4 ++++ .../Services/Wallet/WalletPairService.swift | 13 +++++++++---- Sources/WalletConnectRelay/Dispatching.swift | 5 +++++ Sources/WalletConnectRelay/RelayClient.swift | 4 ++++ Tests/EventsTests/EventsCollectorTests.swift | 4 ++-- 7 files changed, 30 insertions(+), 10 deletions(-) rename Sources/Events/ExecutionTraces/{NewPairingExecutionTraceEvents.swift => PairingExecutionTraceEvents.swift} (83%) diff --git a/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift b/Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift similarity index 83% rename from Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift rename to Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift index bc4d2ba79..8ed89517e 100644 --- a/Sources/Events/ExecutionTraces/NewPairingExecutionTraceEvents.swift +++ b/Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift @@ -1,13 +1,15 @@ import Foundation -public enum NewPairingExecutionTraceEvents: String, TraceEvent { - case pairingStarted = "pairing_started" +public enum PairingExecutionTraceEvents: String, TraceEvent { case pairingUriValidationSuccess = "pairing_uri_validation_success" - case pairingUriNotExpired = "pairing_uri_not_expired" + case pairingStarted = "pairing_started" + case noWssConnection = "no_wss_connection" case storeNewPairing = "store_new_pairing" case subscribingPairingTopic = "subscribing_pairing_topic" case subscribePairingTopicSuccess = "subscribe_pairing_topic_success" + case pairingHasPendingRequest = "pairing_has_pending_request" + case emitSessionProposal = "emit_session_proposal" public var description: String { return self.rawValue @@ -16,7 +18,6 @@ public enum NewPairingExecutionTraceEvents: String, TraceEvent { // Enum for TraceErrorEvents public enum TraceErrorEvents: String, ErrorEvent { - case noWssConnection = "no_wss_connection" case noInternetConnection = "no_internet_connection" case malformedPairingUri = "malformed_pairing_uri" case activePairingAlreadyExists = "active_pairing_already_exists" diff --git a/Sources/WalletConnectNetworking/NetworkInteracting.swift b/Sources/WalletConnectNetworking/NetworkInteracting.swift index a79814399..e916c3f62 100644 --- a/Sources/WalletConnectNetworking/NetworkInteracting.swift +++ b/Sources/WalletConnectNetworking/NetworkInteracting.swift @@ -2,6 +2,7 @@ import Foundation import Combine public protocol NetworkInteracting { + var isSocketConnected: Bool { get } var socketConnectionStatusPublisher: AnyPublisher { get } var networkConnectionStatusPublisher: AnyPublisher { get } var requestPublisher: AnyPublisher<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?), Never> { get } diff --git a/Sources/WalletConnectNetworking/NetworkingInteractor.swift b/Sources/WalletConnectNetworking/NetworkingInteractor.swift index 847606edd..e7c8eb90d 100644 --- a/Sources/WalletConnectNetworking/NetworkingInteractor.swift +++ b/Sources/WalletConnectNetworking/NetworkingInteractor.swift @@ -27,6 +27,10 @@ public class NetworkingInteractor: NetworkInteracting { .eraseToAnyPublisher() } + public var isSocketConnected: Bool { + return relayClient.isSocketConnected + } + public var networkConnectionStatusPublisher: AnyPublisher public var socketConnectionStatusPublisher: AnyPublisher diff --git a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift index e7ccd715e..e66fc0ece 100644 --- a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift +++ b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift @@ -31,18 +31,22 @@ actor WalletPairService { func pair(_ uri: WalletConnectURI) async throws { eventsClient.startTrace(topic: uri.topic) - eventsClient.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) + eventsClient.saveEvent(PairingExecutionTraceEvents.pairingStarted) logger.debug("Pairing with uri: \(uri)") guard try !pairingHasPendingRequest(for: uri.topic) else { + eventsClient.saveEvent(PairingExecutionTraceEvents.pairingHasPendingRequest) logger.debug("Pairing with topic (\(uri.topic)) has pending request") return } - + if !networkingInteractor.isSocketConnected { + eventsClient.saveEvent(PairingExecutionTraceEvents.noWssConnection) + } + let pairing = WCPairing(uri: uri) let symKey = try SymmetricKey(hex: uri.symKey) try kms.setSymmetricKey(symKey, for: pairing.topic) pairingStorage.setPairing(pairing) - eventsClient.saveEvent(NewPairingExecutionTraceEvents.storeNewPairing) + eventsClient.saveEvent(PairingExecutionTraceEvents.storeNewPairing) let networkConnectionStatus = await resolveNetworkConnectionStatus() guard networkConnectionStatus == .connected else { @@ -50,7 +54,7 @@ actor WalletPairService { eventsClient.saveEvent(TraceErrorEvents.noInternetConnection) throw Errors.networkNotConnected } - + eventsClient.saveEvent(PairingExecutionTraceEvents.subscribingPairingTopic) do { try await networkingInteractor.subscribe(topic: pairing.topic) } catch { @@ -81,6 +85,7 @@ extension WalletPairService { guard !pendingRequests.isEmpty else { return false } pendingRequests.forEach { request in + eventsClient.saveEvent(PairingExecutionTraceEvents.emitSessionProposal) networkingInteractor.handleHistoryRequest(topic: topic, request: request) } return true diff --git a/Sources/WalletConnectRelay/Dispatching.swift b/Sources/WalletConnectRelay/Dispatching.swift index 81ede05d7..3af72ce97 100644 --- a/Sources/WalletConnectRelay/Dispatching.swift +++ b/Sources/WalletConnectRelay/Dispatching.swift @@ -3,6 +3,7 @@ import Combine protocol Dispatching { var onMessage: ((String) -> Void)? { get set } + var isSocketConnected: Bool { get } var networkConnectionStatusPublisher: AnyPublisher { get } var socketConnectionStatusPublisher: AnyPublisher { get } func send(_ string: String, completion: @escaping (Error?) -> Void) @@ -32,6 +33,10 @@ final class Dispatcher: NSObject, Dispatching { networkMonitor.networkConnectionStatusPublisher } + var isSocketConnected: Bool { + return networkMonitor.isConnected + } + private let concurrentQueue = DispatchQueue(label: "com.walletconnect.sdk.dispatcher", qos: .utility, attributes: .concurrent) init( diff --git a/Sources/WalletConnectRelay/RelayClient.swift b/Sources/WalletConnectRelay/RelayClient.swift index efa501499..93b33f1c7 100644 --- a/Sources/WalletConnectRelay/RelayClient.swift +++ b/Sources/WalletConnectRelay/RelayClient.swift @@ -22,6 +22,10 @@ public final class RelayClient { var subscriptions: [String: String] = [:] + public var isSocketConnected: Bool { + return dispatcher.isSocketConnected + } + public var messagePublisher: AnyPublisher<(topic: String, message: String, publishedAt: Date), Never> { messagePublisherSubject.eraseToAnyPublisher() } diff --git a/Tests/EventsTests/EventsCollectorTests.swift b/Tests/EventsTests/EventsCollectorTests.swift index 2379c500a..87419fdf9 100644 --- a/Tests/EventsTests/EventsCollectorTests.swift +++ b/Tests/EventsTests/EventsCollectorTests.swift @@ -27,7 +27,7 @@ class EventsCollectorTests: XCTestCase { func testSaveEvent() { eventsCollector.startTrace(topic: "test_topic") - eventsCollector.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) + eventsCollector.saveEvent(PairingExecutionTraceEvents.pairingStarted) XCTAssertEqual(eventsCollector.trace, ["pairing_started"]) XCTAssertEqual(mockStorage.savedEvents.count, 0) @@ -35,7 +35,7 @@ class EventsCollectorTests: XCTestCase { func testSaveErrorEvent() { eventsCollector.startTrace(topic: "test_topic") - eventsCollector.saveEvent(NewPairingExecutionTraceEvents.pairingStarted) + eventsCollector.saveEvent(PairingExecutionTraceEvents.pairingStarted) eventsCollector.saveEvent(TraceErrorEvents.noInternetConnection) XCTAssertEqual(mockStorage.savedEvents.count, 1) From 18bd2cdbe2e88fa64a4c736f044d68a42fc4df26 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 09:20:04 +0200 Subject: [PATCH 11/28] savepoint --- .../SessionApproveExecutionTraceEvents.swift | 2 ++ Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift diff --git a/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift b/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift new file mode 100644 index 000000000..350c82fae --- /dev/null +++ b/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift @@ -0,0 +1,2 @@ + +import Foundation diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index 4f3f0b4c4..5befa4605 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -1,6 +1,5 @@ import Foundation import Combine -import Events final class ApproveEngine { enum Errors: Error { @@ -31,6 +30,7 @@ final class ApproveEngine { private let logger: ConsoleLogging private let rpcHistory: RPCHistory private let authRequestSubscribersTracking: AuthRequestSubscribersTracking + private let eventsClient: EventsClient private var publishers = Set() @@ -47,7 +47,8 @@ final class ApproveEngine { sessionStore: WCSessionStorage, verifyClient: VerifyClientProtocol, rpcHistory: RPCHistory, - authRequestSubscribersTracking: AuthRequestSubscribersTracking + authRequestSubscribersTracking: AuthRequestSubscribersTracking, + eventsClient: EventsClient ) { self.networkingInteractor = networkingInteractor self.proposalPayloadsStore = proposalPayloadsStore @@ -62,6 +63,7 @@ final class ApproveEngine { self.verifyClient = verifyClient self.rpcHistory = rpcHistory self.authRequestSubscribersTracking = authRequestSubscribersTracking + self.eventsClient = eventsClient setupRequestSubscriptions() setupResponseSubscriptions() From 34f30e8d0ab8aeab2dbce17d9599573503b8c0b9 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 09:36:30 +0200 Subject: [PATCH 12/28] Add approve session events --- .../PairingExecutionTraceEvents.swift | 2 +- .../SessionApproveExecutionTraceEvents.swift | 27 ++++++++ .../Services/Wallet/WalletPairService.swift | 6 +- .../Engine/Common/ApproveEngine.swift | 63 ++++++++++++++----- Tests/EventsTests/EventsCollectorTests.swift | 2 +- 5 files changed, 79 insertions(+), 21 deletions(-) diff --git a/Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift b/Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift index 8ed89517e..bfb809dd3 100644 --- a/Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift +++ b/Sources/Events/ExecutionTraces/PairingExecutionTraceEvents.swift @@ -17,7 +17,7 @@ public enum PairingExecutionTraceEvents: String, TraceEvent { } // Enum for TraceErrorEvents -public enum TraceErrorEvents: String, ErrorEvent { +public enum PairingTraceErrorEvents: String, ErrorEvent { case noInternetConnection = "no_internet_connection" case malformedPairingUri = "malformed_pairing_uri" case activePairingAlreadyExists = "active_pairing_already_exists" diff --git a/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift b/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift index 350c82fae..95cc48ca6 100644 --- a/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift +++ b/Sources/Events/ExecutionTraces/SessionApproveExecutionTraceEvents.swift @@ -1,2 +1,29 @@ import Foundation + +public enum SessionApproveExecutionTraceEvents: String, TraceEvent { + case approvingSessionProposal = "approving_session_proposal" + case sessionNamespacesValidationStarted = "session_namespaces_validation_started" + case sessionNamespacesValidationSuccess = "session_namespaces_validation_success" + case responseApproveSent = "response_approve_sent" + case settleRequestSent = "settle_request_sent" + case sessionSettleSuccess = "session_settle_success" + + public var description: String { + return self.rawValue + } +} + +public enum ApproveSessionTraceErrorEvents: String, ErrorEvent { + case sessionNamespacesValidationFailure = "session_namespaces_validation_failure" + case proposalNotFound = "proposal_not_found" + case proposalExpired = "proposal_expired" + case networkNotConnected = "network_not_connected" + case agreementMissingOrInvalid = "agreement_missing_or_invalid" + case relayNotFound = "relay_not_found" + case sessionSettleFailure = "session_settle_failure" + + public var description: String { + return self.rawValue + } +} diff --git a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift index e66fc0ece..c5607aa59 100644 --- a/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift +++ b/Sources/WalletConnectPairing/Services/Wallet/WalletPairService.swift @@ -51,7 +51,7 @@ actor WalletPairService { let networkConnectionStatus = await resolveNetworkConnectionStatus() guard networkConnectionStatus == .connected else { logger.debug("Pairing failed - Network is not connected") - eventsClient.saveEvent(TraceErrorEvents.noInternetConnection) + eventsClient.saveEvent(PairingTraceErrorEvents.noInternetConnection) throw Errors.networkNotConnected } eventsClient.saveEvent(PairingExecutionTraceEvents.subscribingPairingTopic) @@ -59,7 +59,7 @@ actor WalletPairService { try await networkingInteractor.subscribe(topic: pairing.topic) } catch { logger.debug("Failed to subscribe to topic: \(pairing.topic)") - eventsClient.saveEvent(TraceErrorEvents.subscribePairingTopicFailure) + eventsClient.saveEvent(PairingTraceErrorEvents.subscribePairingTopicFailure) throw error } } @@ -73,7 +73,7 @@ extension WalletPairService { } if pairing.active { - eventsClient.saveEvent(TraceErrorEvents.activePairingAlreadyExists) + eventsClient.saveEvent(PairingTraceErrorEvents.activePairingAlreadyExists) throw Errors.pairingAlreadyExist(topic: topic) } diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index 5befa4605..8f65ce772 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -70,12 +70,18 @@ final class ApproveEngine { setupResponseErrorSubscriptions() } + func approveProposal(proposerPubKey: String, validating sessionNamespaces: [String: SessionNamespace], sessionProperties: [String: String]? = nil) async throws -> Session { logger.debug("Approving session proposal") + eventsClient.saveEvent(SessionApproveExecutionTraceEvents.approvingSessionProposal) - guard !sessionNamespaces.isEmpty else { throw Errors.emtySessionNamespacesForbidden } + guard !sessionNamespaces.isEmpty else { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.sessionNamespacesValidationFailure) + throw Errors.emtySessionNamespacesForbidden + } guard let payload = try proposalPayloadsStore.get(key: proposerPubKey) else { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.proposalNotFound) throw Errors.proposalNotFound } @@ -83,31 +89,44 @@ final class ApproveEngine { guard !proposal.isExpired() else { logger.debug("Proposal has expired, topic: \(payload.topic)") + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.proposalExpired) proposalPayloadsStore.delete(forKey: proposerPubKey) throw Errors.proposalExpired } let networkConnectionStatus = await resolveNetworkConnectionStatus() guard networkConnectionStatus == .connected else { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.networkNotConnected) throw Errors.networkNotConnected } let pairingTopic = payload.topic - try Namespace.validate(sessionNamespaces) - try Namespace.validateApproved(sessionNamespaces, against: proposal.requiredNamespaces) + do { + eventsClient.saveEvent(SessionApproveExecutionTraceEvents.sessionNamespacesValidationStarted) + try Namespace.validate(sessionNamespaces) + try Namespace.validateApproved(sessionNamespaces, against: proposal.requiredNamespaces) + eventsClient.saveEvent(SessionApproveExecutionTraceEvents.sessionNamespacesValidationSuccess) + } catch { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.sessionNamespacesValidationFailure) + throw error + } let selfPublicKey = try kms.createX25519KeyPair() guard let agreementKey = try? kms.performKeyAgreement( selfPublicKey: selfPublicKey, peerPublicKey: proposal.proposer.publicKey - ) else { throw Errors.agreementMissingOrInvalid } + ) else { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.agreementMissingOrInvalid) + throw Errors.agreementMissingOrInvalid + } let sessionTopic = agreementKey.derivedTopic() try kms.setAgreementSecret(agreementKey, topic: sessionTopic) guard let relay = proposal.relays.first else { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.relayNotFound) throw Errors.relayNotFound } @@ -128,21 +147,33 @@ final class ApproveEngine { pairingTopic: pairingTopic ) - _ = try await proposeResponseTask - let session: WCSession = try await settleRequestTask + do { + _ = try await proposeResponseTask + eventsClient.saveEvent(SessionApproveExecutionTraceEvents.responseApproveSent) + } catch { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.sessionSettleFailure) + throw error + } - sessionStore.setSession(session) - onSessionSettle?(session.publicRepresentation()) - logger.debug("Session proposal response and settle request have been sent") + do { + let session: WCSession = try await settleRequestTask + sessionStore.setSession(session) + onSessionSettle?(session.publicRepresentation()) + eventsClient.saveEvent(SessionApproveExecutionTraceEvents.sessionSettleSuccess) + logger.debug("Session proposal response and settle request have been sent") - proposalPayloadsStore.delete(forKey: proposerPubKey) - verifyContextStore.delete(forKey: proposerPubKey) + proposalPayloadsStore.delete(forKey: proposerPubKey) + verifyContextStore.delete(forKey: proposerPubKey) - pairingRegisterer.activate( - pairingTopic: payload.topic, - peerMetadata: payload.request.proposer.metadata - ) - return session.publicRepresentation() + pairingRegisterer.activate( + pairingTopic: payload.topic, + peerMetadata: payload.request.proposer.metadata + ) + return session.publicRepresentation() + } catch { + eventsClient.saveEvent(ApproveSessionTraceErrorEvents.sessionSettleFailure) + throw error + } } func reject(proposerPubKey: String, reason: SignReasonCode) async throws { diff --git a/Tests/EventsTests/EventsCollectorTests.swift b/Tests/EventsTests/EventsCollectorTests.swift index 87419fdf9..2da5850cb 100644 --- a/Tests/EventsTests/EventsCollectorTests.swift +++ b/Tests/EventsTests/EventsCollectorTests.swift @@ -36,7 +36,7 @@ class EventsCollectorTests: XCTestCase { func testSaveErrorEvent() { eventsCollector.startTrace(topic: "test_topic") eventsCollector.saveEvent(PairingExecutionTraceEvents.pairingStarted) - eventsCollector.saveEvent(TraceErrorEvents.noInternetConnection) + eventsCollector.saveEvent(PairingTraceErrorEvents.noInternetConnection) XCTAssertEqual(mockStorage.savedEvents.count, 1) let savedEvent = mockStorage.savedEvents.first From a6dfd366b000b3a49381d67e2a280e9d7844a132 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 10:18:03 +0200 Subject: [PATCH 13/28] savepoint --- Sources/Events/EventsClient.swift | 4 ++++ Sources/Events/EventsCollector.swift | 4 ++++ Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift | 5 +++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 1fc63bce3..a9c4c5831 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -27,6 +27,10 @@ public class EventsClient: EventsClientProtocol { eventsCollector.startTrace(topic: topic) } + public func setTopic(_ topic: String) { + eventsCollector.setTopic(topic) + } + // Public method to save event public func saveEvent(_ event: TraceEvent) { eventsCollector.saveEvent(event) diff --git a/Sources/Events/EventsCollector.swift b/Sources/Events/EventsCollector.swift index 09f255dbd..2ace98002 100644 --- a/Sources/Events/EventsCollector.swift +++ b/Sources/Events/EventsCollector.swift @@ -29,6 +29,10 @@ class EventsCollector { self.trace = [] } + func setTopic(_ topic: String) { + self.topic = topic + } + // Function to save event func saveEvent(_ event: TraceEvent) { trace.append(event.description) diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index 8f65ce772..53f19932c 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -84,6 +84,9 @@ final class ApproveEngine { eventsClient.saveEvent(ApproveSessionTraceErrorEvents.proposalNotFound) throw Errors.proposalNotFound } + let pairingTopic = payload.topic + + eventsClient.setTopic(pairingTopic) let proposal = payload.request @@ -100,8 +103,6 @@ final class ApproveEngine { throw Errors.networkNotConnected } - let pairingTopic = payload.topic - do { eventsClient.saveEvent(SessionApproveExecutionTraceEvents.sessionNamespacesValidationStarted) try Namespace.validate(sessionNamespaces) From d2672b4ed9bd36127d220a3bda9c3025331e1b12 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 10:35:59 +0200 Subject: [PATCH 14/28] session authenticate events --- Sources/Events/EventsClient.swift | 5 + .../SessionAuthenticateTraceEvents.swift | 35 ++++++ .../Wallet/SessionAuthenticateResponder.swift | 119 ++++++++++++------ .../Engine/Common/ApproveEngine.swift | 4 +- 4 files changed, 126 insertions(+), 37 deletions(-) create mode 100644 Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index a9c4c5831..16ce1c833 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -3,6 +3,7 @@ import Foundation public protocol EventsClientProtocol { func startTrace(topic: String) func saveEvent(_ event: TraceEvent) + func setTopic(_ topic: String) func sendStoredEvents() async } @@ -63,6 +64,10 @@ public class MockEventsClient: EventsClientProtocol { public func startTrace(topic: String) { startTraceCalled = true } + + public func setTopic(_ topic: String) { + + } public func saveEvent(_ event: TraceEvent) { saveEventCalled = true diff --git a/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift b/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift new file mode 100644 index 000000000..08e5d4b47 --- /dev/null +++ b/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift @@ -0,0 +1,35 @@ +// + +import Foundation + +public enum SessionAuthenticateTraceEvents: String, TraceEvent { + case signatureVerificationStarted = "signature_verification_started" + case signatureVerificationSuccess = "signature_verification_success" + case requestParamsRetrieved = "request_params_retrieved" + case agreementKeysGenerated = "agreement_keys_generated" + case agreementSecretSet = "agreement_secret_set" + case sessionKeysGenerated = "session_keys_generated" + case sessionSecretSet = "session_secret_set" + case responseParamsCreated = "response_params_created" + case responseSent = "response_sent" + + public var description: String { + return self.rawValue + } +} + +public enum SessionAuthenticateErrorEvents: String, ErrorEvent { + case signatureVerificationFailed = "signature_verification_failed" + case requestParamsRetrievalFailed = "request_params_retrieval_failed" + case agreementKeysGenerationFailed = "agreement_keys_generation_failed" + case agreementSecretSetFailed = "agreement_secret_set_failed" + case sessionKeysGenerationFailed = "session_keys_generation_failed" + case sessionSecretSetFailed = "session_secret_set_failed" + case responseParamsCreationFailed = "response_params_creation_failed" + case sessionCreationFailed = "session_creation_failed" + case pairingActivationFailed = "pairing_activation_failed" + + public var description: String { + return self.rawValue + } +} diff --git a/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift b/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift index a4b229830..e5df57e19 100644 --- a/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift +++ b/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift @@ -11,6 +11,7 @@ actor SessionAuthenticateResponder { private let pairingRegisterer: PairingRegisterer private let metadata: AppMetadata private let util: ApproveSessionAuthenticateUtil + private let eventsClient: EventsClientProtocol init( networkingInteractor: NetworkInteracting, @@ -20,7 +21,8 @@ actor SessionAuthenticateResponder { walletErrorResponder: WalletErrorResponder, pairingRegisterer: PairingRegisterer, metadata: AppMetadata, - approveSessionAuthenticateUtil: ApproveSessionAuthenticateUtil + approveSessionAuthenticateUtil: ApproveSessionAuthenticateUtil, + eventsClient: EventsClientProtocol ) { self.networkingInteractor = networkingInteractor self.logger = logger @@ -30,54 +32,101 @@ actor SessionAuthenticateResponder { self.pairingRegisterer = pairingRegisterer self.metadata = metadata self.util = approveSessionAuthenticateUtil + self.eventsClient = eventsClient } func respond(requestId: RPCID, auths: [Cacao]) async throws -> Session? { - try await util.recoverAndVerifySignature(cacaos: auths) - let (sessionAuthenticateRequestParams, pairingTopic) = try util.getsessionAuthenticateRequestParams(requestId: requestId) - let (responseTopic, responseKeys) = try util.generateAgreementKeys(requestParams: sessionAuthenticateRequestParams) - - - try kms.setAgreementSecret(responseKeys, topic: responseTopic) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.signatureVerificationStarted) + do { + try await util.recoverAndVerifySignature(cacaos: auths) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.signatureVerificationSuccess) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.signatureVerificationFailed) + throw error + } + + do { + let (sessionAuthenticateRequestParams, pairingTopic) = try util.getsessionAuthenticateRequestParams(requestId: requestId) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.requestParamsRetrieved) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.requestParamsRetrievalFailed) + throw error + } + + do { + let (responseTopic, responseKeys) = try util.generateAgreementKeys(requestParams: sessionAuthenticateRequestParams) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.agreementKeysGenerated) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.agreementKeysGenerationFailed) + throw error + } + + do { + try kms.setAgreementSecret(responseKeys, topic: responseTopic) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.agreementSecretSet) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.agreementSecretSetFailed) + throw error + } let peerParticipant = sessionAuthenticateRequestParams.requester - let sessionSelfPubKey = try kms.createX25519KeyPair() - let sessionSelfPubKeyHex = sessionSelfPubKey.hexRepresentation - let sessionKeys = try kms.performKeyAgreement(selfPublicKey: sessionSelfPubKey, peerPublicKey: peerParticipant.publicKey) + do { + let sessionSelfPubKey = try kms.createX25519KeyPair() + let sessionSelfPubKeyHex = sessionSelfPubKey.hexRepresentation + let sessionKeys = try kms.performKeyAgreement(selfPublicKey: sessionSelfPubKey, peerPublicKey: peerParticipant.publicKey) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.sessionKeysGenerated) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.sessionKeysGenerationFailed) + throw error + } let sessionTopic = sessionKeys.derivedTopic() - try kms.setAgreementSecret(sessionKeys, topic: sessionTopic) + do { + try kms.setAgreementSecret(sessionKeys, topic: sessionTopic) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.sessionSecretSet) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.sessionSecretSetFailed) + throw error + } let selfParticipant = Participant(publicKey: sessionSelfPubKeyHex, metadata: metadata) let responseParams = SessionAuthenticateResponseParams(responder: selfParticipant, cacaos: auths) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.responseParamsCreated) let response = RPCResponse(id: requestId, result: responseParams) - - try await networkingInteractor.respond( - topic: responseTopic, - response: response, - protocolMethod: SessionAuthenticatedProtocolMethod.responseApprove(), - envelopeType: .type1(pubKey: responseKeys.publicKey.rawRepresentation) - ) - - - let session = try util.createSession( - response: responseParams, - pairingTopic: pairingTopic, - request: sessionAuthenticateRequestParams, - sessionTopic: sessionTopic, - transportType: .relay - ) - - pairingRegisterer.activate( - pairingTopic: pairingTopic, - peerMetadata: sessionAuthenticateRequestParams.requester.metadata - ) - verifyContextStore.delete(forKey: requestId.string) - - return session + do { + try await networkingInteractor.respond( + topic: responseTopic, + response: response, + protocolMethod: SessionAuthenticatedProtocolMethod.responseApprove(), + envelopeType: .type1(pubKey: responseKeys.publicKey.rawRepresentation) + ) + eventsClient.saveEvent(SessionAuthenticateTraceEvents.responseSent) + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.responseSendFailed) + throw error + } + + do { + let session = try util.createSession( + response: responseParams, + pairingTopic: pairingTopic, + request: sessionAuthenticateRequestParams, + sessionTopic: sessionTopic, + transportType: .relay + ) + pairingRegisterer.activate( + pairingTopic: pairingTopic, + peerMetadata: sessionAuthenticateRequestParams.requester.metadata + ) + verifyContextStore.delete(forKey: requestId.string) + return session + } catch { + eventsClient.saveEvent(SessionAuthenticateErrorEvents.sessionCreationFailed) + throw error + } } func respondError(requestId: RPCID) async throws { diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index 53f19932c..1fc5f0fe3 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -30,7 +30,7 @@ final class ApproveEngine { private let logger: ConsoleLogging private let rpcHistory: RPCHistory private let authRequestSubscribersTracking: AuthRequestSubscribersTracking - private let eventsClient: EventsClient + private let eventsClient: EventsClientProtocol private var publishers = Set() @@ -48,7 +48,7 @@ final class ApproveEngine { verifyClient: VerifyClientProtocol, rpcHistory: RPCHistory, authRequestSubscribersTracking: AuthRequestSubscribersTracking, - eventsClient: EventsClient + eventsClient: EventsClientProtocol ) { self.networkingInteractor = networkingInteractor self.proposalPayloadsStore = proposalPayloadsStore From b9f3b56e02d96c4a9225d81375b17bc10c16d9d0 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 10:59:24 +0200 Subject: [PATCH 15/28] fix tests --- Sources/Events/EventsClient.swift | 11 ++--------- Tests/EventsTests/EventsCollectorTests.swift | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 16ce1c833..dd481fbba 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -4,7 +4,6 @@ public protocol EventsClientProtocol { func startTrace(topic: String) func saveEvent(_ event: TraceEvent) func setTopic(_ topic: String) - func sendStoredEvents() async } public class EventsClient: EventsClientProtocol { @@ -37,8 +36,7 @@ public class EventsClient: EventsClientProtocol { eventsCollector.saveEvent(event) } - // Public method to send stored events - public func sendStoredEvents() async { + private func sendStoredEvents() async { let events = eventsCollector.storage.fetchErrorEvents() guard !events.isEmpty else { return } @@ -57,14 +55,13 @@ public class EventsClient: EventsClientProtocol { public class MockEventsClient: EventsClientProtocol { var startTraceCalled = false var saveEventCalled = false - var sendStoredEventsCalled = false public init() {} public func startTrace(topic: String) { startTraceCalled = true } - + public func setTopic(_ topic: String) { } @@ -72,9 +69,5 @@ public class MockEventsClient: EventsClientProtocol { public func saveEvent(_ event: TraceEvent) { saveEventCalled = true } - - public func sendStoredEvents() async { - sendStoredEventsCalled = true - } } #endif diff --git a/Tests/EventsTests/EventsCollectorTests.swift b/Tests/EventsTests/EventsCollectorTests.swift index 2da5850cb..3dc59c7f9 100644 --- a/Tests/EventsTests/EventsCollectorTests.swift +++ b/Tests/EventsTests/EventsCollectorTests.swift @@ -10,7 +10,7 @@ class EventsCollectorTests: XCTestCase { override func setUp() { super.setUp() mockStorage = MockEventStorage() - eventsCollector = EventsCollector(storage: mockStorage, bundleId: "com.wallet.example") + eventsCollector = EventsCollector(storage: mockStorage, logger: ConsoleLoggerMock()) } override func tearDown() { From 97c5f10554a79508571c33e6040d01402bd7fdea Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 11:37:22 +0200 Subject: [PATCH 16/28] savepoint --- Sources/Events/EventStorage.swift | 10 +++++++--- .../Engine/Common/ApproveEngine.swift | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Sources/Events/EventStorage.swift b/Sources/Events/EventStorage.swift index 348e5b7c1..691ef903e 100644 --- a/Sources/Events/EventStorage.swift +++ b/Sources/Events/EventStorage.swift @@ -7,13 +7,17 @@ protocol EventStorage { func clearErrorEvents() } -// Default implementation using UserDefaults class UserDefaultsEventStorage: EventStorage { private let errorEventsKey = "com.walletconnect.sdk.errorEvents" + private let maxEvents = 30 func saveErrorEvent(_ event: Event) { var existingEvents = fetchErrorEvents() existingEvents.append(event) + // Ensure we keep only the last 30 events + if existingEvents.count > maxEvents { + existingEvents = Array(existingEvents.suffix(maxEvents)) + } if let encoded = try? JSONEncoder().encode(existingEvents) { UserDefaults.standard.set(encoded, forKey: errorEventsKey) } @@ -22,7 +26,8 @@ class UserDefaultsEventStorage: EventStorage { func fetchErrorEvents() -> [Event] { if let data = UserDefaults.standard.data(forKey: errorEventsKey), let events = try? JSONDecoder().decode([Event].self, from: data) { - return events + // Return only the last 30 events + return Array(events.suffix(maxEvents)) } return [] } @@ -32,7 +37,6 @@ class UserDefaultsEventStorage: EventStorage { } } - #if DEBUG class MockEventStorage: EventStorage { private(set) var savedEvents: [Event] = [] diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index 1fc5f0fe3..cd127d81a 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -72,6 +72,7 @@ final class ApproveEngine { func approveProposal(proposerPubKey: String, validating sessionNamespaces: [String: SessionNamespace], sessionProperties: [String: String]? = nil) async throws -> Session { + eventsClient.startTrace(topic: "") logger.debug("Approving session proposal") eventsClient.saveEvent(SessionApproveExecutionTraceEvents.approvingSessionProposal) From 791c5ae84c99b11774d39b491035d83dd189af5b Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 12:20:45 +0200 Subject: [PATCH 17/28] savepoint --- Sources/Events/EventsClient.swift | 39 ++++++++++++-- Sources/Events/EventsClientFactory.swift | 3 +- Sources/Events/UserDefaultsStateStorage.swift | 54 +++++++++++++++++++ Sources/WalletConnectSign/Sign/Sign.swift | 3 +- .../Sign/SignClientFactory.swift | 14 +++-- 5 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 Sources/Events/UserDefaultsStateStorage.swift diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index dd481fbba..6a7ed3296 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -4,39 +4,65 @@ public protocol EventsClientProtocol { func startTrace(topic: String) func saveEvent(_ event: TraceEvent) func setTopic(_ topic: String) + func setTelemetryEnabled(_ enabled: Bool) } public class EventsClient: EventsClientProtocol { private let eventsCollector: EventsCollector private let eventsDispatcher: EventsDispatcher private let logger: ConsoleLogging + private var stateStorage: TelemetryStateStorage + private var telemetryEnabled: Bool init( eventsCollector: EventsCollector, eventsDispatcher: EventsDispatcher, - logger: ConsoleLogging + logger: ConsoleLogging, + stateStorage: TelemetryStateStorage ) { self.eventsCollector = eventsCollector self.eventsDispatcher = eventsDispatcher self.logger = logger - Task { await sendStoredEvents() } + self.stateStorage = stateStorage + self.telemetryEnabled = stateStorage.telemetryEnabled + + if telemetryEnabled { + Task { await sendStoredEvents() } + } else { + self.eventsCollector.storage.clearErrorEvents() + } } // Public method to start trace public func startTrace(topic: String) { + guard telemetryEnabled else { return } eventsCollector.startTrace(topic: topic) } public func setTopic(_ topic: String) { + guard telemetryEnabled else { return } eventsCollector.setTopic(topic) } // Public method to save event public func saveEvent(_ event: TraceEvent) { + guard telemetryEnabled else { return } eventsCollector.saveEvent(event) } + // Public method to set telemetry enabled or disabled + public func setTelemetryEnabled(_ enabled: Bool) { + telemetryEnabled = enabled + stateStorage.telemetryEnabled = enabled + if enabled { + Task { await sendStoredEvents() } + } else { + eventsCollector.storage.clearErrorEvents() + } + } + private func sendStoredEvents() async { + guard telemetryEnabled else { return } let events = eventsCollector.storage.fetchErrorEvents() guard !events.isEmpty else { return } @@ -55,6 +81,7 @@ public class EventsClient: EventsClientProtocol { public class MockEventsClient: EventsClientProtocol { var startTraceCalled = false var saveEventCalled = false + var telemetryEnabled = true public init() {} @@ -62,12 +89,14 @@ public class MockEventsClient: EventsClientProtocol { startTraceCalled = true } - public func setTopic(_ topic: String) { - - } + public func setTopic(_ topic: String) {} public func saveEvent(_ event: TraceEvent) { saveEventCalled = true } + + public func setTelemetryEnabled(_ enabled: Bool) { + telemetryEnabled = enabled + } } #endif diff --git a/Sources/Events/EventsClientFactory.swift b/Sources/Events/EventsClientFactory.swift index e8384eac2..98ffdebf4 100644 --- a/Sources/Events/EventsClientFactory.swift +++ b/Sources/Events/EventsClientFactory.swift @@ -17,7 +17,8 @@ public class EventsClientFactory { return EventsClient( eventsCollector: eventsCollector, eventsDispatcher: eventsDispatcher, - logger: logger + logger: logger, + stateStorage: UserDefaultsTelemetryStateStorage() ) } } diff --git a/Sources/Events/UserDefaultsStateStorage.swift b/Sources/Events/UserDefaultsStateStorage.swift new file mode 100644 index 000000000..fa00eee21 --- /dev/null +++ b/Sources/Events/UserDefaultsStateStorage.swift @@ -0,0 +1,54 @@ +import Foundation + +protocol TelemetryStateStorage { + var telemetryEnabled: Bool { get set } +} + +class UserDefaultsTelemetryStateStorage: TelemetryStateStorage { + private let telemetryEnabledKey = "com.walletconnect.sdk.telemetryEnabled" + + var telemetryEnabled: Bool { + get { + if UserDefaults.standard.object(forKey: telemetryEnabledKey) == nil { + return true + } + return UserDefaults.standard.bool(forKey: telemetryEnabledKey) + } + set { + UserDefaults.standard.set(newValue, forKey: telemetryEnabledKey) + } + } + + init() { + if UserDefaults.standard.object(forKey: telemetryEnabledKey) == nil { + // Set default value if not already set + UserDefaults.standard.set(true, forKey: telemetryEnabledKey) + } + } +} + +#if DEBUG +class MockUserDefaultsTelemetryStateStorage: TelemetryStateStorage { + private var mockStorage: [String: Any] = [:] + private let telemetryEnabledKey = "com.walletconnect.sdk.telemetryEnabled" + + var telemetryEnabled: Bool { + get { + if mockStorage[telemetryEnabledKey] == nil { + return true + } + return mockStorage[telemetryEnabledKey] as? Bool ?? true + } + set { + mockStorage[telemetryEnabledKey] = newValue + } + } + + init() { + // Initialize with a default value if not already set + if mockStorage[telemetryEnabledKey] == nil { + mockStorage[telemetryEnabledKey] = true + } + } +} +#endif diff --git a/Sources/WalletConnectSign/Sign/Sign.swift b/Sources/WalletConnectSign/Sign/Sign.swift index 25f88df3e..3205485d6 100644 --- a/Sources/WalletConnectSign/Sign/Sign.swift +++ b/Sources/WalletConnectSign/Sign/Sign.swift @@ -29,7 +29,8 @@ public class Sign { projectId: Networking.projectId, crypto: config.crypto, networkingClient: Networking.interactor, - groupIdentifier: Networking.groupIdentifier + groupIdentifier: Networking.groupIdentifier, + eventsClient: Events.instance ) }() diff --git a/Sources/WalletConnectSign/Sign/SignClientFactory.swift b/Sources/WalletConnectSign/Sign/SignClientFactory.swift index 4acff725c..6a9989112 100644 --- a/Sources/WalletConnectSign/Sign/SignClientFactory.swift +++ b/Sources/WalletConnectSign/Sign/SignClientFactory.swift @@ -17,7 +17,8 @@ public struct SignClientFactory { projectId: String, crypto: CryptoProvider, networkingClient: NetworkingInteractor, - groupIdentifier: String + groupIdentifier: String, + eventsClient: EventsClientProtocol ) -> SignClient { let logger = ConsoleLogger(prefix: "📝", loggingLevel: .off) @@ -37,7 +38,8 @@ public struct SignClientFactory { networkingClient: networkingClient, iatProvider: iatProvider, projectId: projectId, - crypto: crypto + crypto: crypto, + eventsClient: eventsClient ) } @@ -50,7 +52,8 @@ public struct SignClientFactory { networkingClient: NetworkingInteractor, iatProvider: IATProvider, projectId: String, - crypto: CryptoProvider + crypto: CryptoProvider, + eventsClient: EventsClientProtocol ) -> SignClient { let kms = KeyManagementService(keychain: keychainStorage) let rpcHistory = RPCHistoryFactory.createForNetwork(keyValueStorage: keyValueStorage) @@ -83,7 +86,8 @@ public struct SignClientFactory { sessionStore: sessionStore, verifyClient: verifyClient, rpcHistory: rpcHistory, - authRequestSubscribersTracking: authRequestSubscribersTracking + authRequestSubscribersTracking: authRequestSubscribersTracking, + eventsClient: eventsClient ) let cleanupService = SignCleanupService(pairingStore: pairingStore, sessionStore: sessionStore, kms: kms, sessionTopicToProposal: sessionTopicToProposal, networkInteractor: networkingClient, rpcHistory: rpcHistory) let deleteSessionService = DeleteSessionService(networkingInteractor: networkingClient, kms: kms, sessionStore: sessionStore, logger: logger) @@ -125,7 +129,7 @@ public struct SignClientFactory { let linkAuthRequester = LinkAuthRequester(kms: kms, appMetadata: metadata, logger: logger, iatProvader: iatProvider, authResponseTopicRecordsStore: authResponseTopicRecordsStore, linkEnvelopesDispatcher: linkEnvelopesDispatcher, linkModeLinksStore: linkModeLinksStore) let linkAuthRequestSubscriber = LinkAuthRequestSubscriber(logger: logger, kms: kms, envelopesDispatcher: linkEnvelopesDispatcher, verifyClient: verifyClient, verifyContextStore: verifyContextStore) - let relaySessionAuthenticateResponder = SessionAuthenticateResponder(networkingInteractor: networkingClient, logger: logger, kms: kms, verifyContextStore: verifyContextStore, walletErrorResponder: walletErrorResponder, pairingRegisterer: pairingClient, metadata: metadata, approveSessionAuthenticateUtil: approveSessionAuthenticateUtil) + let relaySessionAuthenticateResponder = SessionAuthenticateResponder(networkingInteractor: networkingClient, logger: logger, kms: kms, verifyContextStore: verifyContextStore, walletErrorResponder: walletErrorResponder, pairingRegisterer: pairingClient, metadata: metadata, approveSessionAuthenticateUtil: approveSessionAuthenticateUtil, eventsClient: eventsClient) let linkSessionAuthenticateResponder = LinkSessionAuthenticateResponder(linkEnvelopesDispatcher: linkEnvelopesDispatcher, logger: logger, kms: kms, metadata: metadata, approveSessionAuthenticateUtil: approveSessionAuthenticateUtil, walletErrorResponder: walletErrorResponder) From abdec5b185a7f910cd0be94623c35edf2b092b05 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Jul 2024 15:48:05 +0200 Subject: [PATCH 18/28] savepoint --- .../xcschemes/EventsTests 1.xcscheme | 54 ------------------- .../Sign/SignClientTests.swift | 3 +- .../Web3Wallet/XPlatformW3WTests.swift | 3 +- .../ConfigurationService.swift | 1 + Sources/Events/EventsClient.swift | 21 +++++--- Sources/Events/EventsClientFactory.swift | 2 +- Sources/Events/EventsDispatcher.swift | 11 ++-- .../SessionAuthenticateTraceEvents.swift | 4 +- Sources/Events/NetworkingService.swift | 9 ++-- .../Wallet/SessionAuthenticateResponder.swift | 28 +++++++--- 10 files changed, 50 insertions(+), 86 deletions(-) delete mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme deleted file mode 100644 index 7f7753025..000000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests 1.xcscheme +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/IntegrationTests/Sign/SignClientTests.swift b/Example/IntegrationTests/Sign/SignClientTests.swift index 04c18cc58..31f09a9e3 100644 --- a/Example/IntegrationTests/Sign/SignClientTests.swift +++ b/Example/IntegrationTests/Sign/SignClientTests.swift @@ -62,7 +62,8 @@ final class SignClientTests: XCTestCase { networkingClient: networkingClient, iatProvider: IATProviderMock(), projectId: InputConfig.projectId, - crypto: DefaultCryptoProvider() + crypto: DefaultCryptoProvider(), + eventsClient: MockEventsClient() ) let clientId = try! networkingClient.getClientId() diff --git a/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift b/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift index b01538240..5826e1f1a 100644 --- a/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift +++ b/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift @@ -58,7 +58,8 @@ final class XPlatformW3WTests: XCTestCase { networkingClient: networkingClient, iatProvider: DefaultIATProvider(), projectId: InputConfig.projectId, - crypto: DefaultCryptoProvider() + crypto: DefaultCryptoProvider(), + eventsClient: MockEventsClient() ) w3wClient = Web3WalletClientFactory.create( diff --git a/Example/WalletApp/ApplicationLayer/ConfigurationService.swift b/Example/WalletApp/ApplicationLayer/ConfigurationService.swift index 2eda07ec7..970353746 100644 --- a/Example/WalletApp/ApplicationLayer/ConfigurationService.swift +++ b/Example/WalletApp/ApplicationLayer/ConfigurationService.swift @@ -33,6 +33,7 @@ final class ConfigurationService { Notify.instance.setLogging(level: .debug) Sign.instance.setLogging(level: .debug) + Events.instance.setLogging(level: .debug) if let clientId = try? Networking.interactor.getClientId() { LoggingService.instance.setUpUser(account: importAccount.account.absoluteString, clientId: clientId) diff --git a/Sources/Events/EventsClient.swift b/Sources/Events/EventsClient.swift index 6a7ed3296..f0bcb32c3 100644 --- a/Sources/Events/EventsClient.swift +++ b/Sources/Events/EventsClient.swift @@ -12,7 +12,6 @@ public class EventsClient: EventsClientProtocol { private let eventsDispatcher: EventsDispatcher private let logger: ConsoleLogging private var stateStorage: TelemetryStateStorage - private var telemetryEnabled: Bool init( eventsCollector: EventsCollector, @@ -24,35 +23,39 @@ public class EventsClient: EventsClientProtocol { self.eventsDispatcher = eventsDispatcher self.logger = logger self.stateStorage = stateStorage - self.telemetryEnabled = stateStorage.telemetryEnabled - if telemetryEnabled { + if stateStorage.telemetryEnabled { Task { await sendStoredEvents() } } else { self.eventsCollector.storage.clearErrorEvents() } } + public func setLogging(level: LoggingLevel) { + logger.setLogging(level: level) + } + // Public method to start trace public func startTrace(topic: String) { - guard telemetryEnabled else { return } + guard stateStorage.telemetryEnabled else { return } + logger.debug("Will start trace with topic: \(topic)") eventsCollector.startTrace(topic: topic) } public func setTopic(_ topic: String) { - guard telemetryEnabled else { return } + guard stateStorage.telemetryEnabled else { return } eventsCollector.setTopic(topic) } // Public method to save event public func saveEvent(_ event: TraceEvent) { - guard telemetryEnabled else { return } + guard stateStorage.telemetryEnabled else { return } + logger.debug("Will store an event: \(event)") eventsCollector.saveEvent(event) } // Public method to set telemetry enabled or disabled public func setTelemetryEnabled(_ enabled: Bool) { - telemetryEnabled = enabled stateStorage.telemetryEnabled = enabled if enabled { Task { await sendStoredEvents() } @@ -62,13 +65,15 @@ public class EventsClient: EventsClientProtocol { } private func sendStoredEvents() async { - guard telemetryEnabled else { return } + guard stateStorage.telemetryEnabled else { return } let events = eventsCollector.storage.fetchErrorEvents() guard !events.isEmpty else { return } + logger.debug("Will send events") do { let success: Bool = try await eventsDispatcher.executeWithRetry(events: events) if success { + logger.debug("Events sent successfully") self.eventsCollector.storage.clearErrorEvents() } } catch { diff --git a/Sources/Events/EventsClientFactory.swift b/Sources/Events/EventsClientFactory.swift index 98ffdebf4..43bff4c76 100644 --- a/Sources/Events/EventsClientFactory.swift +++ b/Sources/Events/EventsClientFactory.swift @@ -10,7 +10,7 @@ public class EventsClientFactory { projectId: projectId, sdkVersion: sdkVersion ) - let logger = ConsoleLogger(prefix: "", loggingLevel: .off) + let logger = ConsoleLogger(prefix: "🧚🏻‍♂️", loggingLevel: .off) let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 5, multiplier: 2) let eventsDispatcher = EventsDispatcher(networkingService: networkingService, retryPolicy: retryPolicy) let eventsCollector = EventsCollector(storage: storage, logger: logger) diff --git a/Sources/Events/EventsDispatcher.swift b/Sources/Events/EventsDispatcher.swift index 4df0eaee7..0c347958b 100644 --- a/Sources/Events/EventsDispatcher.swift +++ b/Sources/Events/EventsDispatcher.swift @@ -22,16 +22,19 @@ class EventsDispatcher { var delay = retryPolicy.initialDelay while attempts < retryPolicy.maxAttempts { - attempts += 1 + if attempts > 0 || retryPolicy.initialDelay > 0 { + let actualDelay = retryPolicy.delayOverride ?? delay + try await Task.sleep(nanoseconds: UInt64(actualDelay * Double(NSEC_PER_SEC))) + delay *= retryPolicy.multiplier + } + do { return try await networkingService.sendEvents(events) } catch { + attempts += 1 if attempts >= retryPolicy.maxAttempts { throw error } - let actualDelay = retryPolicy.delayOverride ?? delay - try await Task.sleep(nanoseconds: UInt64(actualDelay * Double(NSEC_PER_SEC))) - delay *= retryPolicy.multiplier } } throw NSError(domain: "EventsDispatcherError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Max retry attempts reached"]) diff --git a/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift b/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift index 08e5d4b47..88b2f0696 100644 --- a/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift +++ b/Sources/Events/ExecutionTraces/SessionAuthenticateTraceEvents.swift @@ -1,4 +1,3 @@ -// import Foundation @@ -25,9 +24,8 @@ public enum SessionAuthenticateErrorEvents: String, ErrorEvent { case agreementSecretSetFailed = "agreement_secret_set_failed" case sessionKeysGenerationFailed = "session_keys_generation_failed" case sessionSecretSetFailed = "session_secret_set_failed" - case responseParamsCreationFailed = "response_params_creation_failed" case sessionCreationFailed = "session_creation_failed" - case pairingActivationFailed = "pairing_activation_failed" + case responseSendFailed = "response_send_failed" public var description: String { return self.rawValue diff --git a/Sources/Events/NetworkingService.swift b/Sources/Events/NetworkingService.swift index 76754849d..a8a03b620 100644 --- a/Sources/Events/NetworkingService.swift +++ b/Sources/Events/NetworkingService.swift @@ -1,11 +1,9 @@ - import Foundation protocol NetworkingServiceProtocol { func sendEvents(_ events: [Event]) async throws -> Bool } - class NetworkingService: NetworkingServiceProtocol { private let session: URLSession private let projectId: String @@ -35,12 +33,11 @@ class NetworkingService: NetworkingServiceProtocol { return } - guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + if let httpResponse = response as? HTTPURLResponse, (200..<300).contains(httpResponse.statusCode) { + continuation.resume(returning: true) + } else { continuation.resume(returning: false) - return } - - continuation.resume(returning: true) } task.priority = URLSessionTask.lowPriority diff --git a/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift b/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift index e5df57e19..dea7e0e9e 100644 --- a/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift +++ b/Sources/WalletConnectSign/Auth/Services/Wallet/SessionAuthenticateResponder.swift @@ -45,16 +45,22 @@ actor SessionAuthenticateResponder { throw error } + let sessionAuthenticateRequestParams: SessionAuthenticateRequestParams + let pairingTopic: String + do { - let (sessionAuthenticateRequestParams, pairingTopic) = try util.getsessionAuthenticateRequestParams(requestId: requestId) + (sessionAuthenticateRequestParams, pairingTopic) = try util.getsessionAuthenticateRequestParams(requestId: requestId) eventsClient.saveEvent(SessionAuthenticateTraceEvents.requestParamsRetrieved) } catch { eventsClient.saveEvent(SessionAuthenticateErrorEvents.requestParamsRetrievalFailed) throw error } + let responseTopic: String + let responseKeys: AgreementKeys + do { - let (responseTopic, responseKeys) = try util.generateAgreementKeys(requestParams: sessionAuthenticateRequestParams) + (responseTopic, responseKeys) = try util.generateAgreementKeys(requestParams: sessionAuthenticateRequestParams) eventsClient.saveEvent(SessionAuthenticateTraceEvents.agreementKeysGenerated) } catch { eventsClient.saveEvent(SessionAuthenticateErrorEvents.agreementKeysGenerationFailed) @@ -71,10 +77,14 @@ actor SessionAuthenticateResponder { let peerParticipant = sessionAuthenticateRequestParams.requester + let sessionSelfPubKey: AgreementPublicKey + let sessionSelfPubKeyHex: String + let sessionKeys: AgreementKeys + do { - let sessionSelfPubKey = try kms.createX25519KeyPair() - let sessionSelfPubKeyHex = sessionSelfPubKey.hexRepresentation - let sessionKeys = try kms.performKeyAgreement(selfPublicKey: sessionSelfPubKey, peerPublicKey: peerParticipant.publicKey) + sessionSelfPubKey = try kms.createX25519KeyPair() + sessionSelfPubKeyHex = sessionSelfPubKey.hexRepresentation + sessionKeys = try kms.performKeyAgreement(selfPublicKey: sessionSelfPubKey, peerPublicKey: peerParticipant.publicKey) eventsClient.saveEvent(SessionAuthenticateTraceEvents.sessionKeysGenerated) } catch { eventsClient.saveEvent(SessionAuthenticateErrorEvents.sessionKeysGenerationFailed) @@ -130,9 +140,11 @@ actor SessionAuthenticateResponder { } func respondError(requestId: RPCID) async throws { - try await walletErrorResponder.respondError(AuthError.userRejeted, requestId: requestId) + do { + try await walletErrorResponder.respondError(AuthError.userRejeted, requestId: requestId) + } catch { + throw error + } verifyContextStore.delete(forKey: requestId.string) } } - - From 4a8c090f07234a8359aa34ebe8b869136616d0e7 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 9 Jul 2024 13:08:14 +0200 Subject: [PATCH 19/28] fix tests --- Tests/TestingUtils/NetworkingInteractorMock.swift | 2 ++ Tests/WalletConnectPairingTests/WalletPairServiceTests.swift | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/TestingUtils/NetworkingInteractorMock.swift b/Tests/TestingUtils/NetworkingInteractorMock.swift index a1fa196ad..65b73ab0c 100644 --- a/Tests/TestingUtils/NetworkingInteractorMock.swift +++ b/Tests/TestingUtils/NetworkingInteractorMock.swift @@ -6,6 +6,8 @@ import WalletConnectKMS import WalletConnectNetworking public class NetworkingInteractorMock: NetworkInteracting { + public var isSocketConnected: Bool = true + private var publishers = Set() diff --git a/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift b/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift index 6def56757..832c5ccad 100644 --- a/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift +++ b/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift @@ -18,7 +18,7 @@ final class WalletPairServiceTestsTests: XCTestCase { storageMock = WCPairingStorageMock() cryptoMock = KeyManagementServiceMock() rpcHistory = RPCHistoryFactory.createForNetwork(keyValueStorage: RuntimeKeyValueStorage()) - service = WalletPairService(networkingInteractor: networkingInteractor, kms: cryptoMock, pairingStorage: storageMock, history: rpcHistory, logger: ConsoleLoggerMock()) + service = WalletPairService(networkingInteractor: networkingInteractor, kms: cryptoMock, pairingStorage: storageMock, history: rpcHistory, logger: ConsoleLoggerMock(), eventsClient: MockEventsClient()) } func testPairWhenNetworkNotConnectedThrows() async { From 51ba84f733653958971352e4e6d959fc8b21c952 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 9 Jul 2024 13:11:32 +0200 Subject: [PATCH 20/28] rename var --- Tests/WalletConnectPairingTests/WalletPairServiceTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift b/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift index 832c5ccad..1aeee96ec 100644 --- a/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift +++ b/Tests/WalletConnectPairingTests/WalletPairServiceTests.swift @@ -5,7 +5,7 @@ import XCTest import WalletConnectUtils import WalletConnectNetworking -final class WalletPairServiceTestsTests: XCTestCase { +final class WalletPairServiceTests: XCTestCase { var service: WalletPairService! var networkingInteractor: NetworkingInteractorMock! From ab47fe1f079e28e07b2c70914350dca8b889107d Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 9 Jul 2024 13:22:37 +0200 Subject: [PATCH 21/28] fix tests --- Tests/WalletConnectSignTests/AppProposalServiceTests.swift | 3 ++- Tests/WalletConnectSignTests/ApproveEngineTests.swift | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/WalletConnectSignTests/AppProposalServiceTests.swift b/Tests/WalletConnectSignTests/AppProposalServiceTests.swift index 18a392325..ae3a4772d 100644 --- a/Tests/WalletConnectSignTests/AppProposalServiceTests.swift +++ b/Tests/WalletConnectSignTests/AppProposalServiceTests.swift @@ -78,7 +78,8 @@ final class AppProposalServiceTests: XCTestCase { sessionStore: WCSessionStorageMock(), verifyClient: VerifyClientMock(), rpcHistory: history, - authRequestSubscribersTracking: AuthRequestSubscribersTracking(logger: logger) + authRequestSubscribersTracking: AuthRequestSubscribersTracking(logger: logger), + eventsClient: MockEventsClient() ) } diff --git a/Tests/WalletConnectSignTests/ApproveEngineTests.swift b/Tests/WalletConnectSignTests/ApproveEngineTests.swift index 585f7e4be..79b2f7996 100644 --- a/Tests/WalletConnectSignTests/ApproveEngineTests.swift +++ b/Tests/WalletConnectSignTests/ApproveEngineTests.swift @@ -52,7 +52,8 @@ final class ApproveEngineTests: XCTestCase { sessionStore: sessionStorageMock, verifyClient: VerifyClientMock(), rpcHistory: history, - authRequestSubscribersTracking: AuthRequestSubscribersTracking(logger: ConsoleLoggerMock()) + authRequestSubscribersTracking: AuthRequestSubscribersTracking(logger: ConsoleLoggerMock()), + eventsClient: MockEventsClient() ) } From a4e1f36c47ecc586a496a9754bc97a01305e40b8 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 9 Jul 2024 13:56:54 +0200 Subject: [PATCH 22/28] fix relay tests --- Tests/RelayerTests/Mocks/DispatcherMock.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/RelayerTests/Mocks/DispatcherMock.swift b/Tests/RelayerTests/Mocks/DispatcherMock.swift index 2e12b6ab2..82dd12c6c 100644 --- a/Tests/RelayerTests/Mocks/DispatcherMock.swift +++ b/Tests/RelayerTests/Mocks/DispatcherMock.swift @@ -4,6 +4,8 @@ import Combine @testable import WalletConnectRelay class DispatcherMock: Dispatching { + var isSocketConnected: Bool = true + private var publishers = Set() private let socketConnectionStatusPublisherSubject = CurrentValueSubject(.disconnected) From cb4eaa244f60226ed30025dda0907bef1a091855 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 9 Jul 2024 19:09:29 +0200 Subject: [PATCH 23/28] savepoint --- .../Misc/NetworkConstants.swift | 3 +- .../WalletConnectRelay/RelayURLFactory.swift | 8 ++--- .../AutomaticSocketConnectionHandler.swift | 24 +++++---------- .../ManualSocketConnectionHandler.swift | 19 ++++-------- .../SocketConnectionHandler.swift | 1 - .../SocketUrlFallbackHandler.swift | 29 ------------------- 6 files changed, 16 insertions(+), 68 deletions(-) delete mode 100644 Sources/WalletConnectRelay/SocketUrlFallbackHandler.swift diff --git a/Sources/WalletConnectRelay/Misc/NetworkConstants.swift b/Sources/WalletConnectRelay/Misc/NetworkConstants.swift index 5a23a21c8..9f2d6f259 100644 --- a/Sources/WalletConnectRelay/Misc/NetworkConstants.swift +++ b/Sources/WalletConnectRelay/Misc/NetworkConstants.swift @@ -1,4 +1,3 @@ enum NetworkConstants { - static var defaultUrl = "relay.walletconnect.com" - static var fallbackUrl = "relay.walletconnect.org" + static var defaultUrl = "relay.walletconnect.org" } diff --git a/Sources/WalletConnectRelay/RelayURLFactory.swift b/Sources/WalletConnectRelay/RelayURLFactory.swift index 20290fd24..5809c89fa 100644 --- a/Sources/WalletConnectRelay/RelayURLFactory.swift +++ b/Sources/WalletConnectRelay/RelayURLFactory.swift @@ -18,19 +18,15 @@ class RelayUrlFactory { self.socketAuthenticator = socketAuthenticator } - func setFallback() { - self.fallback = true - } - func create() -> URL { var components = URLComponents() components.scheme = "wss" - components.host = fallback ? NetworkConstants.fallbackUrl : relayHost + components.host = relayHost components.queryItems = [ URLQueryItem(name: "projectId", value: projectId) ] do { - let authToken = try socketAuthenticator.createAuthToken(url: fallback ? "wss://" + NetworkConstants.fallbackUrl : "wss://" + relayHost) + let authToken = try socketAuthenticator.createAuthToken(url: "wss://" + relayHost) components.queryItems?.append(URLQueryItem(name: "auth", value: authToken)) } catch { // TODO: Handle token creation errors diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift index 3be94af13..a757884c1 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift @@ -14,9 +14,8 @@ class AutomaticSocketConnectionHandler { private let appStateObserver: AppStateObserving private let networkMonitor: NetworkMonitoring private let backgroundTaskRegistrar: BackgroundTaskRegistering - private let defaultTimeout: Int = 5 + private let defaultTimeout: Int = 30 private let logger: ConsoleLogging - private var socketUrlFallbackHandler: SocketUrlFallbackHandler private var publishers = Set() private let concurrentQueue = DispatchQueue(label: "com.walletconnect.sdk.automatic_socket_connection", qos: .utility, attributes: .concurrent) @@ -27,24 +26,16 @@ class AutomaticSocketConnectionHandler { appStateObserver: AppStateObserving = AppStateObserver(), backgroundTaskRegistrar: BackgroundTaskRegistering = BackgroundTaskRegistrar(), logger: ConsoleLogging, - socketUrlFallbackHandler: SocketUrlFallbackHandler ) { self.appStateObserver = appStateObserver self.socket = socket self.networkMonitor = networkMonitor self.backgroundTaskRegistrar = backgroundTaskRegistrar self.logger = logger - self.socketUrlFallbackHandler = socketUrlFallbackHandler setUpStateObserving() setUpNetworkMonitoring() - socketUrlFallbackHandler.onTryReconnect = { [unowned self] in - Task(priority: .high) { - await tryReconect() - } - } - connect() } @@ -63,7 +54,7 @@ class AutomaticSocketConnectionHandler { } if !self.socket.isConnected { self.logger.debug("Connection timed out, initiating fallback...") - self.socketUrlFallbackHandler.handleFallbackIfNeeded(error: .connectionFailed) + retryToConnect() } timer.cancel() } @@ -99,6 +90,12 @@ class AutomaticSocketConnectionHandler { socket.disconnect() } + private func retryToConnect() { + if !socket.isConnected { + socket.connect() + } + } + private func reconnectIfNeeded() { if !socket.isConnected { socket.connect() @@ -109,11 +106,6 @@ class AutomaticSocketConnectionHandler { // MARK: - SocketConnectionHandler extension AutomaticSocketConnectionHandler: SocketConnectionHandler { - func tryReconect() async { - guard await appStateObserver.currentState == .foreground else { return } - reconnectIfNeeded() - } - func handleConnect() throws { throw Errors.manualSocketConnectionForbidden } diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift index d0589ca9e..100f8bd3c 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift @@ -4,23 +4,14 @@ class ManualSocketConnectionHandler: SocketConnectionHandler { private let socket: WebSocketConnecting private let logger: ConsoleLogging - private let defaultTimeout: Int = 5 - private var socketUrlFallbackHandler: SocketUrlFallbackHandler + private let defaultTimeout: Int = 30 private let concurrentQueue = DispatchQueue(label: "com.walletconnect.sdk.manual_socket_connection", attributes: .concurrent) init( socket: WebSocketConnecting, - logger: ConsoleLogging, - socketUrlFallbackHandler: SocketUrlFallbackHandler) { + logger: ConsoleLogging) { self.socket = socket self.logger = logger - self.socketUrlFallbackHandler = socketUrlFallbackHandler - - socketUrlFallbackHandler.onTryReconnect = { [unowned self] in - Task(priority: .high) { - await tryReconect() - } - } } func handleConnect() throws { @@ -34,8 +25,8 @@ class ManualSocketConnectionHandler: SocketConnectionHandler { return } if !self.socket.isConnected { - self.logger.debug("Connection timed out, initiating fallback...") - self.socketUrlFallbackHandler.handleFallbackIfNeeded(error: .connectionFailed) + self.logger.debug("Connection timed out, will rety to connect...") + retryToConnect() } timer.cancel() } @@ -51,7 +42,7 @@ class ManualSocketConnectionHandler: SocketConnectionHandler { // ManualSocketConnectionHandler does not support reconnection logic } - func tryReconect() async { + private func retryToConnect() { if !socket.isConnected { socket.connect() } diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/SocketConnectionHandler.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/SocketConnectionHandler.swift index 91284893b..4ac3046dd 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/SocketConnectionHandler.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/SocketConnectionHandler.swift @@ -4,5 +4,4 @@ protocol SocketConnectionHandler { func handleConnect() throws func handleDisconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws func handleDisconnection() async - func tryReconect() async } diff --git a/Sources/WalletConnectRelay/SocketUrlFallbackHandler.swift b/Sources/WalletConnectRelay/SocketUrlFallbackHandler.swift deleted file mode 100644 index dea30eecd..000000000 --- a/Sources/WalletConnectRelay/SocketUrlFallbackHandler.swift +++ /dev/null @@ -1,29 +0,0 @@ -import Foundation - -class SocketUrlFallbackHandler { - private let relayUrlFactory: RelayUrlFactory - private var logger: ConsoleLogging - private var socket: WebSocketConnecting - private let networkMonitor: NetworkMonitoring - var onTryReconnect: (()->())? - - init( - relayUrlFactory: RelayUrlFactory, - logger: ConsoleLogging, - socket: WebSocketConnecting, - networkMonitor: NetworkMonitoring) { - self.relayUrlFactory = relayUrlFactory - self.logger = logger - self.socket = socket - self.networkMonitor = networkMonitor - } - - func handleFallbackIfNeeded(error: NetworkError) { - if error == .connectionFailed && socket.request.url?.host == NetworkConstants.defaultUrl { - logger.debug("[WebSocket] - Fallback to \(NetworkConstants.fallbackUrl)") - relayUrlFactory.setFallback() - socket.request.url = relayUrlFactory.create() - onTryReconnect?() - } - } -} From b410943c4eadfd30c544bd9cfa5bb8b64bbb29cf Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 10 Jul 2024 08:08:58 +0200 Subject: [PATCH 24/28] remove fallback handler --- Sources/WalletConnectRelay/RelayClientFactory.swift | 11 +++-------- .../AutomaticSocketConnectionHandler.swift | 8 ++++---- .../ManualSocketConnectionHandler.swift | 2 +- Tests/RelayerTests/DispatcherTests.swift | 3 +-- .../ManualSocketConnectionHandlerTests.swift | 3 +-- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/Sources/WalletConnectRelay/RelayClientFactory.swift b/Sources/WalletConnectRelay/RelayClientFactory.swift index 3a4097336..2120b720e 100644 --- a/Sources/WalletConnectRelay/RelayClientFactory.swift +++ b/Sources/WalletConnectRelay/RelayClientFactory.swift @@ -61,16 +61,11 @@ public struct RelayClientFactory { if let bundleId = Bundle.main.bundleIdentifier { socket.request.addValue(bundleId, forHTTPHeaderField: "Origin") } - let socketFallbackHandler = SocketUrlFallbackHandler( - relayUrlFactory: relayUrlFactory, - logger: logger, - socket: socket, - networkMonitor: networkMonitor - ) + var socketConnectionHandler: SocketConnectionHandler! switch socketConnectionType { - case .automatic: socketConnectionHandler = AutomaticSocketConnectionHandler(socket: socket, logger: logger, socketUrlFallbackHandler: socketFallbackHandler) - case .manual: socketConnectionHandler = ManualSocketConnectionHandler(socket: socket, logger: logger, socketUrlFallbackHandler: socketFallbackHandler) + case .automatic: socketConnectionHandler = AutomaticSocketConnectionHandler(socket: socket, logger: logger) + case .manual: socketConnectionHandler = ManualSocketConnectionHandler(socket: socket, logger: logger) } let dispatcher = Dispatcher( diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift index a757884c1..c9ea12219 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift @@ -14,7 +14,7 @@ class AutomaticSocketConnectionHandler { private let appStateObserver: AppStateObserving private let networkMonitor: NetworkMonitoring private let backgroundTaskRegistrar: BackgroundTaskRegistering - private let defaultTimeout: Int = 30 + private let defaultTimeout: Int = 60 private let logger: ConsoleLogging private var publishers = Set() @@ -25,7 +25,7 @@ class AutomaticSocketConnectionHandler { networkMonitor: NetworkMonitoring = NetworkMonitor(), appStateObserver: AppStateObserving = AppStateObserver(), backgroundTaskRegistrar: BackgroundTaskRegistering = BackgroundTaskRegistrar(), - logger: ConsoleLogging, + logger: ConsoleLogging ) { self.appStateObserver = appStateObserver self.socket = socket @@ -53,7 +53,7 @@ class AutomaticSocketConnectionHandler { return } if !self.socket.isConnected { - self.logger.debug("Connection timed out, initiating fallback...") + self.logger.debug("Connection timed out, will rety to connect...") retryToConnect() } timer.cancel() @@ -92,7 +92,7 @@ class AutomaticSocketConnectionHandler { private func retryToConnect() { if !socket.isConnected { - socket.connect() + connect() } } diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift index 100f8bd3c..04152bd21 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/ManualSocketConnectionHandler.swift @@ -4,7 +4,7 @@ class ManualSocketConnectionHandler: SocketConnectionHandler { private let socket: WebSocketConnecting private let logger: ConsoleLogging - private let defaultTimeout: Int = 30 + private let defaultTimeout: Int = 60 private let concurrentQueue = DispatchQueue(label: "com.walletconnect.sdk.manual_socket_connection", attributes: .concurrent) init( diff --git a/Tests/RelayerTests/DispatcherTests.swift b/Tests/RelayerTests/DispatcherTests.swift index 4a58cfd97..e8b0de168 100644 --- a/Tests/RelayerTests/DispatcherTests.swift +++ b/Tests/RelayerTests/DispatcherTests.swift @@ -71,8 +71,7 @@ final class DispatcherTests: XCTestCase { projectId: "1012db890cf3cfb0c1cdc929add657ba", socketAuthenticator: socketAuthenticator ) - let socketUrlFallbackHandler = SocketUrlFallbackHandler(relayUrlFactory: relayUrlFactory, logger: logger, socket: webSocket, networkMonitor: networkMonitor) - let socketConnectionHandler = ManualSocketConnectionHandler(socket: webSocket, logger: logger, socketUrlFallbackHandler: socketUrlFallbackHandler) + let socketConnectionHandler = ManualSocketConnectionHandler(socket: webSocket, logger: logger) sut = Dispatcher( socketFactory: webSocketFactory, relayUrlFactory: relayUrlFactory, diff --git a/Tests/RelayerTests/ManualSocketConnectionHandlerTests.swift b/Tests/RelayerTests/ManualSocketConnectionHandlerTests.swift index 6f8a939cb..d86fbc9cf 100644 --- a/Tests/RelayerTests/ManualSocketConnectionHandlerTests.swift +++ b/Tests/RelayerTests/ManualSocketConnectionHandlerTests.swift @@ -22,9 +22,8 @@ final class ManualSocketConnectionHandlerTests: XCTestCase { projectId: "1012db890cf3cfb0c1cdc929add657ba", socketAuthenticator: socketAuthenticator ) - let socketUrlFallbackHandler = SocketUrlFallbackHandler(relayUrlFactory: relayUrlFactory, logger: ConsoleLoggerMock(), socket: socket, networkMonitor: networkMonitor) - sut = ManualSocketConnectionHandler(socket: socket, logger: ConsoleLoggerMock(), socketUrlFallbackHandler: socketUrlFallbackHandler) + sut = ManualSocketConnectionHandler(socket: socket, logger: ConsoleLoggerMock()) } func testHandleDisconnect() { From dbbd7f9e423418cda6ff1625862d95a19d0fdd5e Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 10 Jul 2024 08:10:03 +0200 Subject: [PATCH 25/28] fix tests --- .../RelayerTests/AutomaticSocketConnectionHandlerTests.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tests/RelayerTests/AutomaticSocketConnectionHandlerTests.swift b/Tests/RelayerTests/AutomaticSocketConnectionHandlerTests.swift index b29a830ba..368d25da4 100644 --- a/Tests/RelayerTests/AutomaticSocketConnectionHandlerTests.swift +++ b/Tests/RelayerTests/AutomaticSocketConnectionHandlerTests.swift @@ -28,14 +28,12 @@ final class AutomaticSocketConnectionHandlerTests: XCTestCase { socketAuthenticator: socketAuthenticator ) backgroundTaskRegistrar = BackgroundTaskRegistrarMock() - let socketUrlFallbackHandler = SocketUrlFallbackHandler(relayUrlFactory: relayUrlFactory, logger: ConsoleLoggerMock(), socket: webSocket, networkMonitor: networkMonitor) sut = AutomaticSocketConnectionHandler( socket: webSocketSession, networkMonitor: networkMonitor, appStateObserver: appStateObserver, backgroundTaskRegistrar: backgroundTaskRegistrar, - logger: ConsoleLoggerMock(), - socketUrlFallbackHandler: socketUrlFallbackHandler + logger: ConsoleLoggerMock() ) } From 96a1ae89dfa5ba75f576af36b70b6bc023d50b3c Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 10 Jul 2024 13:04:55 +0200 Subject: [PATCH 26/28] fix tests --- Example/RelayIntegrationTests/RelayClientEndToEndTests.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift b/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift index eef6758de..e3888e786 100644 --- a/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift +++ b/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift @@ -52,9 +52,7 @@ final class RelayClientEndToEndTests: XCTestCase { socketAuthenticator: socketAuthenticator ) - let socketUrlFallbackHandler = SocketUrlFallbackHandler(relayUrlFactory: relayUrlFactory, logger: logger, socket: socket, networkMonitor: networkMonitor) - - let socketConnectionHandler = AutomaticSocketConnectionHandler(socket: socket, logger: logger, socketUrlFallbackHandler: socketUrlFallbackHandler) + let socketConnectionHandler = AutomaticSocketConnectionHandler(socket: socket, logger: logger) let dispatcher = Dispatcher( socketFactory: webSocketFactory, relayUrlFactory: urlFactory, From 73e39aa595e99ea5ccaea4f89dc43525be7906b5 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 11 Jul 2024 15:23:18 +0200 Subject: [PATCH 27/28] fix linkmode response encoding --- .../WalletConnectSign/Auth/Link/LinkEnvelopesDispatcher.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WalletConnectSign/Auth/Link/LinkEnvelopesDispatcher.swift b/Sources/WalletConnectSign/Auth/Link/LinkEnvelopesDispatcher.swift index bd7d093a1..5eec32a99 100644 --- a/Sources/WalletConnectSign/Auth/Link/LinkEnvelopesDispatcher.swift +++ b/Sources/WalletConnectSign/Auth/Link/LinkEnvelopesDispatcher.swift @@ -129,7 +129,7 @@ final class LinkEnvelopesDispatcher { } private func serializeAndCreateUrl(peerUniversalLink: String, encodable: Encodable, envelopeType: Envelope.EnvelopeType, topic: String) throws -> URL { - let envelope = try serializer.serialize(topic: topic, encodable: encodable, envelopeType: envelopeType) + let envelope = try serializer.serialize(topic: topic, encodable: encodable, envelopeType: envelopeType, codingType: .base64UrlEncoded) guard var components = URLComponents(string: peerUniversalLink) else { throw URLError(.badURL) } From a19598716a8bf50dc48eacf272c7219da4a7b9a3 Mon Sep 17 00:00:00 2001 From: llbartekll Date: Sun, 14 Jul 2024 16:46:26 +0000 Subject: [PATCH 28/28] Set User Agent --- Sources/WalletConnectRelay/PackageConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WalletConnectRelay/PackageConfig.json b/Sources/WalletConnectRelay/PackageConfig.json index ec58e3328..c09ac47c5 100644 --- a/Sources/WalletConnectRelay/PackageConfig.json +++ b/Sources/WalletConnectRelay/PackageConfig.json @@ -1 +1 @@ -{"version": "1.19.4"} +{"version": "1.19.5"}