Skip to content

Commit

Permalink
Merge pull request #1251 from WalletConnect/pairing-delete-publish
Browse files Browse the repository at this point in the history
Pairing delete publisher
  • Loading branch information
llbartekll authored Dec 7, 2023
2 parents 62471fc + 0ed11f4 commit 8b2e3c2
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"repositoryURL": "https://github.com/mixpanel/mixpanel-swift",
"state": {
"branch": "master",
"revision": "1ce27d937009d5ecce74dad97d69898ffea49c75",
"revision": "c6336881a077d283db6f6d6e2f242977250230bd",
"version": null
}
},
Expand Down Expand Up @@ -69,8 +69,8 @@
"repositoryURL": "https://github.com/getsentry/sentry-cocoa.git",
"state": {
"branch": null,
"revision": "14aa6e47b03b820fd2b338728637570b9e969994",
"version": "8.12.0"
"revision": "74cf23b2946c92550fb1185612077151497e648e",
"version": "8.17.1"
}
},
{
Expand Down
106 changes: 42 additions & 64 deletions Example/IntegrationTests/Pairing/PairingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,95 +23,61 @@ final class PairingTests: XCTestCase {

private var publishers = [AnyCancellable]()

func makeClientDependencies(prefix: String) -> (PairingClient, NetworkingInteractor, KeychainStorageProtocol, KeyValueStorage) {
func makeClients(prefix: String, includeAuth: Bool = true) -> (PairingClient, AuthClient?) {
let keychain = KeychainStorageMock()
let keyValueStorage = RuntimeKeyValueStorage()

let relayLogger = ConsoleLogger(prefix: prefix + " [Relay]", loggingLevel: .debug)
let pairingLogger = ConsoleLogger(prefix: prefix + " [Pairing]", loggingLevel: .debug)
let networkingLogger = ConsoleLogger(prefix: prefix + " [Networking]", loggingLevel: .debug)
let logger = ConsoleLogger(prefix: prefix, loggingLevel: .debug)

let relayClient = RelayClientFactory.create(
relayHost: InputConfig.relayHost,
projectId: InputConfig.projectId,
keyValueStorage: RuntimeKeyValueStorage(),
keychainStorage: keychain,
socketFactory: DefaultSocketFactory(),
logger: relayLogger)
logger: logger)

let networkingClient = NetworkingClientFactory.create(
relayClient: relayClient,
logger: networkingLogger,
logger: logger,
keychainStorage: keychain,
keyValueStorage: keyValueStorage)

let pairingClient = PairingClientFactory.create(
logger: pairingLogger,
logger: logger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
networkingClient: networkingClient)
let clientId = try! networkingClient.getClientId()
networkingLogger.debug("My client id is: \(clientId)")

return (pairingClient, networkingClient, keychain, keyValueStorage)
}

func makeDappClients() {
let prefix = "🤖 Dapp: "
let (pairingClient, networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix)
let notifyLogger = ConsoleLogger(prefix: prefix + " [Notify]", loggingLevel: .debug)
appPairingClient = pairingClient

appAuthClient = AuthClientFactory.create(
metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "wcdapp://", universal: nil)),
projectId: InputConfig.projectId,
crypto: DefaultCryptoProvider(),
logger: notifyLogger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
networkingClient: networkingInteractor,
pairingRegisterer: pairingClient,
iatProvider: IATProviderMock())
}

func makeWalletClients() {
let prefix = "🐶 Wallet: "
let (pairingClient, networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix)
let notifyLogger = ConsoleLogger(prefix: prefix + " [Notify]", loggingLevel: .debug)
let defaults = RuntimeKeyValueStorage()
walletPairingClient = pairingClient
let historyClient = HistoryClientFactory.create(
historyUrl: "https://history.walletconnect.com",
relayUrl: "wss://relay.walletconnect.com",
keyValueStorage: defaults,
keychain: keychain,
logger: notifyLogger
)
appAuthClient = AuthClientFactory.create(
metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)),
projectId: InputConfig.projectId,
crypto: DefaultCryptoProvider(),
logger: notifyLogger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
networkingClient: networkingInteractor,
pairingRegisterer: pairingClient,
iatProvider: IATProviderMock())
}

func makeWalletPairingClient() {
let prefix = "🐶 Wallet: "
let (pairingClient, _, _, _) = makeClientDependencies(prefix: prefix)
walletPairingClient = pairingClient
let clientId = try! networkingClient.getClientId()
logger.debug("My client id is: \(clientId)")

if includeAuth {
let authClient = AuthClientFactory.create(
metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)),
projectId: InputConfig.projectId,
crypto: DefaultCryptoProvider(),
logger: logger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
networkingClient: networkingClient,
pairingRegisterer: pairingClient,
iatProvider: IATProviderMock())

return (pairingClient, authClient)
} else {
return (pairingClient, nil)
}
}

override func setUp() {
makeDappClients()
(appPairingClient, appAuthClient) = makeClients(prefix: "🤖 Dapp: ")
(walletPairingClient, _) = makeClients(prefix: "🐶 Wallet: ", includeAuth: false)
}

func testPing() async {
let expectation = expectation(description: "expects ping response")
makeWalletClients()
let uri = try! await appPairingClient.create()
try? await walletPairingClient.pair(uri: uri)
try! await walletPairingClient.ping(topic: uri.topic)
Expand All @@ -124,7 +90,6 @@ final class PairingTests: XCTestCase {
}

func testResponseErrorForMethodUnregistered() async {
makeWalletPairingClient()
let expectation = expectation(description: "wallet responds unsupported method for unregistered method")

appAuthClient.authResponsePublisher.sink { (_, response) in
Expand All @@ -134,14 +99,27 @@ final class PairingTests: XCTestCase {

let uri = try! await appPairingClient.create()

try? await walletPairingClient.pair(uri: uri)
try! await walletPairingClient.pair(uri: uri)

try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}

func testDisconnect() {
// TODO
func testDisconnect() async {

let expectation = expectation(description: "wallet disconnected pairing")


walletPairingClient.pairingDeletePublisher.sink { _ in
expectation.fulfill()
}.store(in: &publishers)

let uri = try! await appPairingClient.create()

try? await walletPairingClient.pair(uri: uri)

try! await appPairingClient.disconnect(topic: uri.topic)
wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}
}
15 changes: 11 additions & 4 deletions Sources/WalletConnectPairing/PairingClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ public class PairingClient: PairingRegisterer, PairingInteracting, PairingClient
public var pingResponsePublisher: AnyPublisher<(String), Never> {
pingResponsePublisherSubject.eraseToAnyPublisher()
}
public var pairingDeletePublisher: AnyPublisher<(code: Int, message: String), Never> {
pairingDeleteRequestSubscriber.deletePublisherSubject.eraseToAnyPublisher()
}

public let socketConnectionStatusPublisher: AnyPublisher<SocketConnectionStatus, Never>

private let pairingStorage: WCPairingStorage
Expand All @@ -17,9 +21,10 @@ public class PairingClient: PairingRegisterer, PairingInteracting, PairingClient
private let networkingInteractor: NetworkInteracting
private let pairingRequestsSubscriber: PairingRequestsSubscriber
private let pairingsProvider: PairingsProvider
private let deletePairingService: DeletePairingService
private let pairingDeleteRequester: PairingDeleteRequester
private let resubscribeService: PairingResubscribeService
private let expirationService: ExpirationService
private let pairingDeleteRequestSubscriber: PairingDeleteRequestSubscriber

private let cleanupService: PairingCleanupService

Expand All @@ -33,7 +38,8 @@ public class PairingClient: PairingRegisterer, PairingInteracting, PairingClient
networkingInteractor: NetworkInteracting,
logger: ConsoleLogging,
walletPairService: WalletPairService,
deletePairingService: DeletePairingService,
pairingDeleteRequester: PairingDeleteRequester,
pairingDeleteRequestSubscriber: PairingDeleteRequestSubscriber,
resubscribeService: PairingResubscribeService,
expirationService: ExpirationService,
pairingRequestsSubscriber: PairingRequestsSubscriber,
Expand All @@ -49,7 +55,8 @@ public class PairingClient: PairingRegisterer, PairingInteracting, PairingClient
self.networkingInteractor = networkingInteractor
self.socketConnectionStatusPublisher = socketConnectionStatusPublisher
self.logger = logger
self.deletePairingService = deletePairingService
self.pairingDeleteRequester = pairingDeleteRequester
self.pairingDeleteRequestSubscriber = pairingDeleteRequestSubscriber
self.appPairActivateService = appPairActivateService
self.resubscribeService = resubscribeService
self.expirationService = expirationService
Expand Down Expand Up @@ -112,7 +119,7 @@ public class PairingClient: PairingRegisterer, PairingInteracting, PairingClient
}

public func disconnect(topic: String) async throws {
try await deletePairingService.delete(topic: topic)
try await pairingDeleteRequester.delete(topic: topic)
}

public func validatePairingExistance(_ topic: String) throws {
Expand Down
6 changes: 4 additions & 2 deletions Sources/WalletConnectPairing/PairingClientFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,21 @@ public struct PairingClientFactory {
let pairingRequestsSubscriber = PairingRequestsSubscriber(networkingInteractor: networkingClient, pairingStorage: pairingStore, logger: logger)
let pairingsProvider = PairingsProvider(pairingStorage: pairingStore)
let cleanupService = PairingCleanupService(pairingStore: pairingStore, kms: kms)
let deletePairingService = DeletePairingService(networkingInteractor: networkingClient, kms: kms, pairingStorage: pairingStore, logger: logger)
let pairingDeleteRequester = PairingDeleteRequester(networkingInteractor: networkingClient, kms: kms, pairingStorage: pairingStore, logger: logger)
let pingService = PairingPingService(pairingStorage: pairingStore, networkingInteractor: networkingClient, logger: logger)
let appPairActivateService = AppPairActivationService(pairingStorage: pairingStore, logger: logger)
let expirationService = ExpirationService(pairingStorage: pairingStore, networkInteractor: networkingClient, kms: kms)
let resubscribeService = PairingResubscribeService(networkInteractor: networkingClient, pairingStorage: pairingStore)
let pairingDeleteRequestSubscriber = PairingDeleteRequestSubscriber(networkingInteractor: networkingClient, kms: kms, pairingStorage: pairingStore, logger: logger)

return PairingClient(
pairingStorage: pairingStore,
appPairService: appPairService,
networkingInteractor: networkingClient,
logger: logger,
walletPairService: walletPairService,
deletePairingService: deletePairingService,
pairingDeleteRequester: pairingDeleteRequester,
pairingDeleteRequestSubscriber: pairingDeleteRequestSubscriber,
resubscribeService: resubscribeService,
expirationService: expirationService,
pairingRequestsSubscriber: pairingRequestsSubscriber,
Expand Down
1 change: 1 addition & 0 deletions Sources/WalletConnectPairing/PairingClientProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Combine

public protocol PairingClientProtocol {
var logsPublisher: AnyPublisher<Log, Never> {get}
var pairingDeletePublisher: AnyPublisher<(code: Int, message: String), Never> {get}
func pair(uri: WalletConnectURI) async throws
func disconnect(topic: String) async throws
func getPairings() -> [Pairing]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

import Foundation

struct PairingDeleteParams: Codable {
let code: Int
let message: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Combine

public final class PairingDeleteRequestSubscriber {
private let networkingInteractor: NetworkInteracting
private let logger: ConsoleLogging
private let pairingStorage: WCPairingStorage
private let kms: KeyManagementServiceProtocol
let deletePublisherSubject = PassthroughSubject<(code: Int, message: String), Never>()

private var publishers = [AnyCancellable]()

public init(
networkingInteractor: NetworkInteracting,
kms: KeyManagementServiceProtocol,
pairingStorage: WCPairingStorage,
logger: ConsoleLogging
) {
self.networkingInteractor = networkingInteractor
self.kms = kms
self.pairingStorage = pairingStorage
self.logger = logger
subscribeDeleteRequest()
}

private func subscribeDeleteRequest() {
let method = PairingProtocolMethod.delete
networkingInteractor.requestSubscription(on: method)
.sink { [unowned self] (payload: RequestSubscriptionPayload<PairingDeleteParams>) in

let topic = payload.topic
logger.debug("Received pairing delete request")
pairingStorage.delete(topic: topic)
kms.deleteSymmetricKey(for: topic)
networkingInteractor.unsubscribe(topic: topic)

deletePublisherSubject.send((code: payload.request.code, message: payload.request.message))
Task(priority: .high) {
try? await networkingInteractor.respondSuccess(topic: payload.topic, requestId: payload.id, protocolMethod: method)
}
}
.store(in: &publishers)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

class DeletePairingService {
class PairingDeleteRequester {
private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementServiceProtocol
private let pairingStorage: WCPairingStorage
Expand All @@ -19,8 +19,9 @@ class DeletePairingService {
func delete(topic: String) async throws {
let reason = PairingReasonCode.userDisconnected
let protocolMethod = PairingProtocolMethod.delete
let pairingDeleteParams = PairingDeleteParams(code: reason.code, message: reason.message)
logger.debug("Will delete pairing for reason: message: \(reason.message) code: \(reason.code)")
let request = RPCRequest(method: protocolMethod.method, params: reason)
let request = RPCRequest(method: protocolMethod.method, params: pairingDeleteParams)
try await networkingInteractor.request(request, topic: topic, protocolMethod: protocolMethod)
pairingStorage.delete(topic: topic)
kms.deleteSymmetricKey(for: topic)
Expand Down
4 changes: 4 additions & 0 deletions Sources/Web3Wallet/Web3WalletClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public class Web3WalletClient {
signClient.sessionResponsePublisher.eraseToAnyPublisher()
}

public var pairingDeletePublisher: AnyPublisher<(code: Int, message: String), Never> {
pairingClient.pairingDeletePublisher
}

public var logsPublisher: AnyPublisher<Log, Never> {
return signClient.logsPublisher
.merge(with: pairingClient.logsPublisher)
Expand Down
9 changes: 8 additions & 1 deletion Tests/Web3WalletTests/Mocks/PairingClientMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import Combine
@testable import WalletConnectPairing

final class PairingClientMock: PairingClientProtocol {
private var logsSubject = PassthroughSubject<WalletConnectUtils.Log, Never>()
var pairingDeletePublisher: AnyPublisher<(code: Int, message: String), Never> {
pairingDeletePublisherSubject.eraseToAnyPublisher()
}

var pairingDeletePublisherSubject = PassthroughSubject<(code: Int, message: String), Never>()


var logsSubject = PassthroughSubject<WalletConnectUtils.Log, Never>()

var logsPublisher: AnyPublisher<WalletConnectUtils.Log, Never> {
return logsSubject.eraseToAnyPublisher()
Expand Down

0 comments on commit 8b2e3c2

Please sign in to comment.