Skip to content

Commit

Permalink
Merge pull request #541 from WalletConnect/wallet-pairing-integration
Browse files Browse the repository at this point in the history
[Apps] Wallet pairing integration
  • Loading branch information
llbartekll authored Oct 13, 2022
2 parents 2dba95c + 276e2bf commit b73ccf1
Show file tree
Hide file tree
Showing 15 changed files with 65 additions and 49 deletions.
4 changes: 3 additions & 1 deletion Example/DApp/Auth/AuthCoordinator.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import SwiftUI
import Auth
import WalletConnectPairing

final class AuthCoordinator {

Expand Down Expand Up @@ -30,7 +31,8 @@ final class AuthCoordinator {
url: "wallet.connect",
icons: ["https://avatars.githubusercontent.com/u/37784886"])

Auth.configure(metadata: metadata, account: nil)
Pair.configure(metadata: metadata)
Auth.configure(account: nil)

navigationController.viewControllers = [authViewController]
}
Expand Down
3 changes: 2 additions & 1 deletion Example/DApp/Sign/Connect/ConnectViewController.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import Foundation
import UIKit
import WalletConnectSign
import WalletConnectPairing

class ConnectViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let uri: WalletConnectURI
let activePairings: [Pairing] = Sign.instance.getPairings()
let activePairings: [Pairing] = Pair.instance.getPairings()
let segmentedControl = UISegmentedControl(items: ["Pairings", "New Pairing"])

init(uri: WalletConnectURI) {
Expand Down
6 changes: 4 additions & 2 deletions Example/DApp/Sign/SelectChain/SelectChainViewController.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import WalletConnectSign
import WalletConnectPairing
import UIKit
import Combine

Expand Down Expand Up @@ -34,8 +35,9 @@ class SelectChainViewController: UIViewController, UITableViewDataSource {
let blockchains: Set<Blockchain> = [Blockchain("eip155:1")!, Blockchain("eip155:137")!]
let namespaces: [String: ProposalNamespace] = ["eip155": ProposalNamespace(chains: blockchains, methods: methods, events: [], extensions: nil)]
Task {
let uri = try await Sign.instance.connect(requiredNamespaces: namespaces)
showConnectScreen(uri: uri!)
let uri = try await Pair.instance.create()
try await Sign.instance.connect(requiredNamespaces: namespaces, topic: uri.topic)
showConnectScreen(uri: uri)
}
}

Expand Down
5 changes: 3 additions & 2 deletions Example/ExampleApp/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Combine
import WalletConnectSign
import WalletConnectNetworking
import WalletConnectRelay
import WalletConnectPairing
import Starscream

extension WebSocket: WebSocketConnecting { }
Expand All @@ -27,7 +28,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
icons: ["https://avatars.githubusercontent.com/u/37784886"])

Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory())
Sign.configure(metadata: metadata)
Pair.configure(metadata: metadata)
#if DEBUG
if CommandLine.arguments.contains("-cleanInstall") {
try? Sign.instance.cleanup()
Expand Down Expand Up @@ -56,7 +57,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {

let wcUri = url.absoluteString.deletingPrefix("https://walletconnect.com/wc?uri=")
Task(priority: .high) {
try! await Sign.instance.pair(uri: WalletConnectURI(string: wcUri)!)
try! await Pair.instance.pair(uri: WalletConnectURI(string: wcUri)!)
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion Example/ExampleApp/Wallet/WalletViewController.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import UIKit
import WalletConnectSign
import WalletConnectUtils
import WalletConnectPairing
import WalletConnectRouter
import Web3
import CryptoSwift
Expand Down Expand Up @@ -122,7 +123,7 @@ final class WalletViewController: UIViewController {
print("[WALLET] Pairing to: \(uri)")
Task {
do {
try await Sign.instance.pair(uri: uri)
try await Pair.instance.pair(uri: uri)
} catch {
print("[DAPP] Pairing connect error: \(error)")
}
Expand Down
18 changes: 0 additions & 18 deletions Example/IntegrationTests/Sign/SignClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,24 +134,6 @@ final class SignClientTests: XCTestCase {
wait(for: [sessionDeleteExpectation], timeout: InputConfig.defaultTimeout)
}

func testPairingPing() async throws {
let pongResponseExpectation = expectation(description: "Ping sender receives a pong response")

let uri = try await dapp.client.connect(requiredNamespaces: ProposalNamespace.stubRequired())!
try await wallet.client.pair(uri: uri)

let pairing = wallet.client.getPairings().first!

wallet.onPing = { topic in
XCTAssertEqual(topic, pairing.topic)
pongResponseExpectation.fulfill()
}

try await wallet.client.ping(topic: pairing.topic)

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

func testSessionPing() async throws {
let expectation = expectation(description: "Proposer receives ping response")

Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/Auth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class Auth {
metadata: config.metadata,
account: config.account,
networkingClient: Networking.instance,
pairingRegisterer: Pair.instance
pairingRegisterer: Pair.instance as! PairingRegisterer
)
}()

Expand Down
2 changes: 1 addition & 1 deletion Sources/WalletConnectPairing/Pair.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Combine
public class Pair {

/// Pairing client instance
public static var instance: PairingClient = {
public static var instance: PairingInteracting = {
guard let config = Pair.config else {
fatalError("Error - you must call Pair.configure(_:) before accessing the shared instance.")
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/WalletConnectPairing/PairingClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import WalletConnectNetworking
import Combine
import JSONRPC

public class PairingClient: PairingRegisterer {
public class PairingClient: PairingRegisterer, PairingInteracting {
public var pingResponsePublisher: AnyPublisher<(String), Never> {
pingResponsePublisherSubject.eraseToAnyPublisher()
}
Expand Down
18 changes: 18 additions & 0 deletions Sources/WalletConnectPairing/PairingInteracting.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import WalletConnectUtils

public protocol PairingInteracting {
func pair(uri: WalletConnectURI) async throws

func create() async throws -> WalletConnectURI

func getPairings() -> [Pairing]

func getPairing(for topic: String) throws -> Pairing

func ping(topic: String) async throws

func disconnect(topic: String) async throws

func cleanup() throws
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Foundation
import WalletConnectKMS
import WalletConnectUtils
import WalletConnectPairing

final class CleanupService {

Expand Down
14 changes: 4 additions & 10 deletions Sources/WalletConnectSign/Services/DisconnectService.swift
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
import Foundation
import WalletConnectPairing

class DisconnectService {
enum Errors: Error {
case objectForTopicNotFound
case sessionForTopicNotFound
}

private let deleteSessionService: DeleteSessionService
private let sessionStorage: WCSessionStorage
private let pairingClient: PairingClient

init(deleteSessionService: DeleteSessionService,
sessionStorage: WCSessionStorage,
pairingClient: PairingClient) {
sessionStorage: WCSessionStorage) {
self.deleteSessionService = deleteSessionService
self.sessionStorage = sessionStorage
self.pairingClient = pairingClient
}

func disconnect(topic: String) async throws {
if let _ = try? pairingClient.getPairing(for: topic) {
try await pairingClient.disconnect(topic: topic)
} else if sessionStorage.hasSession(forTopic: topic) {
if sessionStorage.hasSession(forTopic: topic) {
try await deleteSessionService.delete(topic: topic)
} else {
throw Errors.objectForTopicNotFound
throw Errors.sessionForTopicNotFound
}
}
}
2 changes: 1 addition & 1 deletion Sources/WalletConnectSign/Sign/Sign.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Sign {
return SignClientFactory.create(
metadata: Sign.metadata ?? Pair.metadata,
relayClient: Relay.instance,
pairingClient: Pair.instance,
pairingClient: Pair.instance as! PairingClient,
networkingClient: Networking.instance
)
}()
Expand Down
32 changes: 24 additions & 8 deletions Sources/WalletConnectSign/Sign/SignClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import WalletConnectPairing
///
/// Access via `Sign.instance`
public final class SignClient {
enum Errors: Error {
case sessionForTopicNotFound
}

// MARK: - Public Properties

Expand Down Expand Up @@ -165,6 +168,7 @@ public final class SignClient {
/// - requiredNamespaces: required namespaces for a session
/// - topic: Optional parameter - use it if you already have an established pairing with peer client.
/// - Returns: Pairing URI that should be shared with responder out of bound. Common way is to present it as a QR code. Pairing URI will be nil if you are going to establish a session on existing Pairing and `topic` function parameter was provided.
@available(*, deprecated, message: "use Pair.instance.create() and connect(requiredNamespaces: [String: ProposalNamespace]): instead")
public func connect(requiredNamespaces: [String: ProposalNamespace], topic: String? = nil) async throws -> WalletConnectURI? {
logger.debug("Connecting Application")
if let topic = topic {
Expand All @@ -186,13 +190,29 @@ public final class SignClient {
}
}

/// For a dApp to propose a session to a wallet.
/// Function will propose a session on existing pairing.
/// - Parameters:
/// - requiredNamespaces: required namespaces for a session
/// - topic: pairing topic
public func connect(requiredNamespaces: [String: ProposalNamespace], topic: String) async throws {
logger.debug("Connecting Application")
try pairingClient.validatePairingExistance(topic)
try await appProposeService.propose(
pairingTopic: topic,
namespaces: requiredNamespaces,
relay: RelayProtocolOptions(protocol: "irn", data: nil)
)
}

/// For wallet to receive a session proposal from a dApp
/// Responder should call this function in order to accept peer's pairing and be able to subscribe for future session proposals.
/// - Parameter uri: Pairing URI that is commonly presented as a QR code by a dapp.
///
/// Should Error:
/// - When URI has invalid format or missing params
/// - When topic is already in use
@available(*, deprecated, message: "use Pair.instance.pair(uri: WalletConnectURI): instead")
public func pair(uri: WalletConnectURI) async throws {
try await pairingClient.pair(uri: uri)
}
Expand Down Expand Up @@ -251,17 +271,12 @@ public final class SignClient {
///
/// Should Error:
/// - When the session topic is not found
/// - When the response is neither result or error
///
/// - Parameters:
/// - topic: Topic of a session or a pairing
/// - completion: Result will be success on response or an error
/// - topic: Topic of a session
public func ping(topic: String) async throws {
if let _ = try? pairingClient.validatePairingExistance(topic) {
try await pairingPingService.ping(topic: topic)
} else if sessionEngine.hasSession(for: topic) {
try await sessionPingService.ping(topic: topic)
}
guard sessionEngine.hasSession(for: topic) else { throw Errors.sessionForTopicNotFound }
try await sessionPingService.ping(topic: topic)
}

/// For the wallet to emit an event to a dApp
Expand Down Expand Up @@ -297,6 +312,7 @@ public final class SignClient {

/// Query pairings
/// - Returns: All pairings
@available(*, deprecated, message: "use Pair.instance.getPairings(uri: WalletConnectURI): instead")
public func getPairings() -> [Pairing] {
pairingClient.getPairings()
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/WalletConnectSign/Sign/SignClientFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public struct SignClientFactory {
let approveEngine = ApproveEngine(networkingInteractor: networkingClient, proposalPayloadsStore: proposalPayloadsStore, sessionToPairingTopic: sessionToPairingTopic, pairingRegisterer: pairingClient, metadata: metadata, kms: kms, logger: logger, pairingStore: pairingStore, sessionStore: sessionStore)
let cleanupService = CleanupService(pairingStore: pairingStore, sessionStore: sessionStore, kms: kms, sessionToPairingTopic: sessionToPairingTopic)
let deleteSessionService = DeleteSessionService(networkingInteractor: networkingClient, kms: kms, sessionStore: sessionStore, logger: logger)
let disconnectService = DisconnectService(deleteSessionService: deleteSessionService, sessionStorage: sessionStore, pairingClient: pairingClient)
let disconnectService = DisconnectService(deleteSessionService: deleteSessionService, sessionStorage: sessionStore)
let sessionPingService = SessionPingService(sessionStorage: sessionStore, networkingInteractor: networkingClient, logger: logger)
let pairingPingService = PairingPingService(pairingStorage: pairingStore, networkingInteractor: networkingClient, logger: logger)
let appProposerService = AppProposeService(metadata: metadata, networkingInteractor: networkingClient, kms: kms, logger: logger)
Expand Down

0 comments on commit b73ccf1

Please sign in to comment.