From 3fec3ed8beb30efdce2a2322d134404db4a9b30d Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 16 Jun 2025 09:59:20 +0200 Subject: [PATCH 1/5] add connectlinkmode method --- .../Services/App/AppProposeService.swift | 56 +++++++++++++++++++ .../WalletConnectSign/Sign/SignClient.swift | 21 +++++++ 2 files changed, 77 insertions(+) diff --git a/Sources/WalletConnectSign/Services/App/AppProposeService.swift b/Sources/WalletConnectSign/Services/App/AppProposeService.swift index 94ffcbe60..b3bc221fe 100644 --- a/Sources/WalletConnectSign/Services/App/AppProposeService.swift +++ b/Sources/WalletConnectSign/Services/App/AppProposeService.swift @@ -53,3 +53,59 @@ final class AppProposeService { try await networkingInteractor.request(request, topic: pairingTopic, protocolMethod: protocolMethod) } } + + +final class LinkAppProposeService { + private let metadata: AppMetadata + private let kms: KeyManagementServiceProtocol + let linkEnvelopesDispatcher: LinkEnvelopesDispatcher + + private let logger: ConsoleLogging + + init( + metadata: AppMetadata, + linkEnvelopesDispatcher: LinkEnvelopesDispatcher, + kms: KeyManagementServiceProtocol, + logger: ConsoleLogging + ) { + self.metadata = metadata + self.linkEnvelopesDispatcher = linkEnvelopesDispatcher + self.kms = kms + self.logger = logger + } + + func propose( + namespaces: [String: ProposalNamespace], + optionalNamespaces: [String: ProposalNamespace]? = nil, + sessionProperties: [String: String]? = nil, + scopedProperties: [String: String]? = nil, + walletUniversalLink: String + ) async throws -> String { + try Namespace.validate(namespaces) + if let optionalNamespaces { + try Namespace.validate(optionalNamespaces) + } + if let sessionProperties { + try SessionProperties.validate(sessionProperties) + } + let protocolMethod = SessionProposeProtocolMethod.responseApprove() + let publicKey = try! kms.createX25519KeyPair() + let proposer = Participant( + publicKey: publicKey.hexRepresentation, + metadata: metadata) + + let proposal = SessionProposal( + relays: [], + proposer: proposer, + requiredNamespaces: namespaces, + optionalNamespaces: optionalNamespaces ?? [:], + sessionProperties: sessionProperties, + scopedProperties: scopedProperties + ) + + let request = RPCRequest(method: protocolMethod.method, params: proposal) + let envelope = try await linkEnvelopesDispatcher.request(topic: UUID().uuidString,request: request, peerUniversalLink: walletUniversalLink, envelopeType: .type2) + + return envelope + } +} diff --git a/Sources/WalletConnectSign/Sign/SignClient.swift b/Sources/WalletConnectSign/Sign/SignClient.swift index 734173c48..f779bc6a3 100644 --- a/Sources/WalletConnectSign/Sign/SignClient.swift +++ b/Sources/WalletConnectSign/Sign/SignClient.swift @@ -308,6 +308,27 @@ public final class SignClient: SignClientProtocol { return try await authenticateTransportTypeSwitcher.authenticate(params, walletUniversalLink: walletUniversalLink) } + let linkAppProposeService: LinkAppProposeService! +#if DEBUG + public func connectLinkMode( + requiredNamespaces: [String: ProposalNamespace], + optionalNamespaces: [String: ProposalNamespace]? = nil, + sessionProperties: [String: String]? = nil, + scopedProperties: [String: String]? = nil, + walletUniversalLink: String + ) async throws -> WalletConnectURI? { + logger.debug("Connecting Application") + + try await linkAppProposeService.propose( + namespaces: requiredNamespaces, + optionalNamespaces: optionalNamespaces, + sessionProperties: sessionProperties, + scopedProperties: scopedProperties, + walletUniversalLink: walletUniversalLink + ) + return nil + } +#endif #if DEBUG @discardableResult public func authenticateLinkMode( From fa556b6b76d5c3a76f666368c87e0fead5fe715e Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 16 Jun 2025 10:01:55 +0200 Subject: [PATCH 2/5] savepoint --- Sources/WalletConnectSign/Sign/SignClient.swift | 11 ++++++----- .../WalletConnectSign/Sign/SignClientFactory.swift | 5 ++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Sources/WalletConnectSign/Sign/SignClient.swift b/Sources/WalletConnectSign/Sign/SignClient.swift index f779bc6a3..832cd0e5d 100644 --- a/Sources/WalletConnectSign/Sign/SignClient.swift +++ b/Sources/WalletConnectSign/Sign/SignClient.swift @@ -231,7 +231,8 @@ public final class SignClient: SignClientProtocol { sessionResponderDispatcher: SessionResponderDispatcher, linkSessionRequestResponseSubscriber: LinkSessionRequestResponseSubscriber, authenticateTransportTypeSwitcher: AuthenticateTransportTypeSwitcher, - messageVerifier: MessageVerifier + messageVerifier: MessageVerifier, + linkAppProposeService: LinkAppProposeService ) { self.logger = logger self.networkingClient = networkingClient @@ -267,6 +268,7 @@ public final class SignClient: SignClientProtocol { self.linkSessionRequestResponseSubscriber = linkSessionRequestResponseSubscriber self.authenticateTransportTypeSwitcher = authenticateTransportTypeSwitcher self.messageVerifier = messageVerifier + self.linkAppProposeService = linkAppProposeService setUpConnectionObserving() setUpEnginesCallbacks() @@ -308,7 +310,7 @@ public final class SignClient: SignClientProtocol { return try await authenticateTransportTypeSwitcher.authenticate(params, walletUniversalLink: walletUniversalLink) } - let linkAppProposeService: LinkAppProposeService! + let linkAppProposeService: LinkAppProposeService #if DEBUG public func connectLinkMode( requiredNamespaces: [String: ProposalNamespace], @@ -316,17 +318,16 @@ public final class SignClient: SignClientProtocol { sessionProperties: [String: String]? = nil, scopedProperties: [String: String]? = nil, walletUniversalLink: String - ) async throws -> WalletConnectURI? { + ) async throws -> String { logger.debug("Connecting Application") - try await linkAppProposeService.propose( + return try await linkAppProposeService.propose( namespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, sessionProperties: sessionProperties, scopedProperties: scopedProperties, walletUniversalLink: walletUniversalLink ) - return nil } #endif diff --git a/Sources/WalletConnectSign/Sign/SignClientFactory.swift b/Sources/WalletConnectSign/Sign/SignClientFactory.swift index 4f2d8ecad..b2de67419 100644 --- a/Sources/WalletConnectSign/Sign/SignClientFactory.swift +++ b/Sources/WalletConnectSign/Sign/SignClientFactory.swift @@ -146,6 +146,8 @@ public struct SignClientFactory { let linkSessionRequestResponseSubscriber = LinkSessionRequestResponseSubscriber(envelopesDispatcher: linkEnvelopesDispatcher, eventsClient: eventsClient) let authenticateTransportTypeSwitcher = AuthenticateTransportTypeSwitcher(linkAuthRequester: linkAuthRequester, pairingClient: pairingClient, logger: logger, appRequestService: appRequestService, appProposeService: appProposerService) + + let linkAppProposeService = LinkAppProposeService(metadata: metadata, linkEnvelopesDispatcher: linkEnvelopesDispatcher, kms: kms, logger: logger) let client = SignClient( logger: logger, @@ -181,7 +183,8 @@ public struct SignClientFactory { sessionResponderDispatcher: sessionResponderDispatcher, linkSessionRequestResponseSubscriber: linkSessionRequestResponseSubscriber, authenticateTransportTypeSwitcher: authenticateTransportTypeSwitcher, - messageVerifier: signatureVerifier + messageVerifier: signatureVerifier, + linkAppProposeService: linkAppProposeService ) return client } From 08d8e7146619b7f706c11c2e4b5f67ecac9c769e Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 16 Jun 2025 10:19:46 +0200 Subject: [PATCH 3/5] savepoin --- Example/DApp/Modules/Sign/SignPresenter.swift | 19 +++++++++++++++++++ Example/DApp/Modules/Sign/SignView.swift | 12 ++++++++++++ .../Auth/Link/LinkAuthRequestSubscriber.swift | 2 ++ 3 files changed, 33 insertions(+) diff --git a/Example/DApp/Modules/Sign/SignPresenter.swift b/Example/DApp/Modules/Sign/SignPresenter.swift index 8c95927cb..3f1b2ae5e 100644 --- a/Example/DApp/Modules/Sign/SignPresenter.swift +++ b/Example/DApp/Modules/Sign/SignPresenter.swift @@ -116,6 +116,25 @@ final class SignPresenter: ObservableObject { } } + @MainActor + func connectWalletWithSessionProposeLinkMode() { + Task { + do { + ActivityIndicatorManager.shared.start() + let _ = try await Sign.instance.connectLinkMode( + requiredNamespaces: Proposal.requiredNamespaces, + optionalNamespaces: Proposal.optionalNamespaces, + walletUniversalLink: "https://lab.web3modal.com/wallet" + ) + ActivityIndicatorManager.shared.stop() +// router.presentNewPairing(walletConnectUri: walletConnectUri!) + } catch { + AlertPresenter.present(message: error.localizedDescription, type: .error) + ActivityIndicatorManager.shared.stop() + } + } + } + @MainActor func openConfiguration() { router.openConfig() diff --git a/Example/DApp/Modules/Sign/SignView.swift b/Example/DApp/Modules/Sign/SignView.swift index c87e890c5..35cc52071 100644 --- a/Example/DApp/Modules/Sign/SignView.swift +++ b/Example/DApp/Modules/Sign/SignView.swift @@ -79,6 +79,18 @@ struct SignView: View { .background(Color(red: 95/255, green: 159/255, blue: 248/255)) .cornerRadius(16) } + + Button { + presenter.connectWalletWithSessionProposeLinkMode() + } label: { + Text("Session Propose Link Mode") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(Color(red: 95/255, green: 159/255, blue: 248/255)) + .cornerRadius(16) + } } .padding(.top, 10) } diff --git a/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift b/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift index 99000ef64..66e01fe16 100644 --- a/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift +++ b/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift @@ -61,3 +61,5 @@ class LinkAuthRequestSubscriber { } } + + From 3b6f959e80f479c93ff29c671a6ee533d8337e0b Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 16 Jun 2025 10:22:40 +0200 Subject: [PATCH 4/5] add LinkModeSessionProposalSubscriber --- .../Auth/Link/LinkAuthRequestSubscriber.swift | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift b/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift index 66e01fe16..1ea7862aa 100644 --- a/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift +++ b/Sources/WalletConnectSign/Auth/Link/LinkAuthRequestSubscriber.swift @@ -62,4 +62,57 @@ class LinkAuthRequestSubscriber { } +class LinkModeSessionProposalSubscriber { + private let logger: ConsoleLogging + private let kms: KeyManagementServiceProtocol + private var publishers = [AnyCancellable]() + private let envelopesDispatcher: LinkEnvelopesDispatcher + private let verifyClient: VerifyClientProtocol + private let verifyContextStore: CodableStore + + + var onSessionProposal: ((Session.Proposal, VerifyContext?) -> Void)? + + init( + logger: ConsoleLogging, + kms: KeyManagementServiceProtocol, + envelopesDispatcher: LinkEnvelopesDispatcher, + verifyClient: VerifyClientProtocol, + verifyContextStore: CodableStore + ) { + self.logger = logger + self.kms = kms + self.envelopesDispatcher = envelopesDispatcher + self.verifyClient = verifyClient + self.verifyContextStore = verifyContextStore + + + subscribeForSessionProposal() + } + + private func subscribeForSessionProposal() { + envelopesDispatcher + .requestSubscription(on: SessionProposeProtocolMethod.responseApprove().method) + .sink { [unowned self] (payload: RequestSubscriptionPayload) in + + + let proposal = payload.request.publicRepresentation(pairingTopic: payload.topic) + let metadata = payload.request.proposer.metadata + + guard let redirect = metadata.redirect, + let universalLink = redirect.universal else { + logger.warn("redirect property not present") + return + } + + let verifyContext = verifyClient.createVerifyContextForLinkMode( + redirectUniversalLink: universalLink, + domain: metadata.url + ) + + onSessionProposal?(proposal, verifyContext) + }.store(in: &publishers) + } +} + From d376f3ccd6e32d6fa2141471afbfb0e3c9e8a5da Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 16 Jun 2025 11:04:33 +0200 Subject: [PATCH 5/5] savepoint --- Sources/WalletConnectSign/Sign/SignClient.swift | 8 +++++++- Sources/WalletConnectSign/Sign/SignClientFactory.swift | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Sources/WalletConnectSign/Sign/SignClient.swift b/Sources/WalletConnectSign/Sign/SignClient.swift index 832cd0e5d..a0aed0fa8 100644 --- a/Sources/WalletConnectSign/Sign/SignClient.swift +++ b/Sources/WalletConnectSign/Sign/SignClient.swift @@ -193,6 +193,7 @@ public final class SignClient: SignClientProtocol { private let sessionResponderDispatcher: SessionResponderDispatcher private let linkSessionRequestResponseSubscriber: LinkSessionRequestResponseSubscriber private let messageVerifier: MessageVerifier + private let linkModeSessionProposalSubscriber: LinkModeSessionProposalSubscriber private var publishers = Set() @@ -232,7 +233,8 @@ public final class SignClient: SignClientProtocol { linkSessionRequestResponseSubscriber: LinkSessionRequestResponseSubscriber, authenticateTransportTypeSwitcher: AuthenticateTransportTypeSwitcher, messageVerifier: MessageVerifier, - linkAppProposeService: LinkAppProposeService + linkAppProposeService: LinkAppProposeService, + linkModeSessionProposalSubscriber: LinkModeSessionProposalSubscriber ) { self.logger = logger self.networkingClient = networkingClient @@ -269,6 +271,7 @@ public final class SignClient: SignClientProtocol { self.authenticateTransportTypeSwitcher = authenticateTransportTypeSwitcher self.messageVerifier = messageVerifier self.linkAppProposeService = linkAppProposeService + self.linkModeSessionProposalSubscriber = linkModeSessionProposalSubscriber setUpConnectionObserving() setUpEnginesCallbacks() @@ -545,6 +548,9 @@ public final class SignClient: SignClientProtocol { approveEngine.onSessionProposal = { [unowned self] (proposal, context) in sessionProposalPublisherSubject.send((proposal, context)) } + linkModeSessionProposalSubscriber.onSessionProposal = { [unowned self] (proposal, context) in + sessionProposalPublisherSubject.send((proposal, context)) + } approveEngine.onSessionRejected = { [unowned self] proposal, reason in sessionRejectionPublisherSubject.send((proposal, reason)) } diff --git a/Sources/WalletConnectSign/Sign/SignClientFactory.swift b/Sources/WalletConnectSign/Sign/SignClientFactory.swift index b2de67419..fd18a7d6e 100644 --- a/Sources/WalletConnectSign/Sign/SignClientFactory.swift +++ b/Sources/WalletConnectSign/Sign/SignClientFactory.swift @@ -148,6 +148,8 @@ public struct SignClientFactory { let authenticateTransportTypeSwitcher = AuthenticateTransportTypeSwitcher(linkAuthRequester: linkAuthRequester, pairingClient: pairingClient, logger: logger, appRequestService: appRequestService, appProposeService: appProposerService) let linkAppProposeService = LinkAppProposeService(metadata: metadata, linkEnvelopesDispatcher: linkEnvelopesDispatcher, kms: kms, logger: logger) + + let linkModeSessionProposalSubscriber = LinkModeSessionProposalSubscriber(logger: logger, kms: kms, envelopesDispatcher: linkEnvelopesDispatcher, verifyClient: verifyClient, verifyContextStore: verifyContextStore) let client = SignClient( logger: logger, @@ -184,7 +186,8 @@ public struct SignClientFactory { linkSessionRequestResponseSubscriber: linkSessionRequestResponseSubscriber, authenticateTransportTypeSwitcher: authenticateTransportTypeSwitcher, messageVerifier: signatureVerifier, - linkAppProposeService: linkAppProposeService + linkAppProposeService: linkAppProposeService, + linkModeSessionProposalSubscriber: linkModeSessionProposalSubscriber ) return client }