Skip to content

Commit

Permalink
Merge pull request #839 from WalletConnect/pending-session-proposal
Browse files Browse the repository at this point in the history
[W3W] Add pending proposals
  • Loading branch information
Alexander authored Aug 1, 2023
2 parents 7bae06f + a45dc7b commit ff1dbbc
Show file tree
Hide file tree
Showing 26 changed files with 305 additions and 53 deletions.
4 changes: 2 additions & 2 deletions Example/DApp/Sign/ResponseViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ class ResponseViewController: UIViewController {
let record = Sign.instance.getSessionRequestRecord(id: response.id)!
switch response.result {
case .response(let response):
responseView.nameLabel.text = "Received Response\n\(record.method)"
responseView.nameLabel.text = "Received Response\n\(record.request.method)"
responseView.descriptionLabel.text = try! response.get(String.self).description
case .error(let error):
responseView.nameLabel.text = "Received Error\n\(record.method)"
responseView.nameLabel.text = "Received Error\n\(record.request.method)"
responseView.descriptionLabel.text = error.message
}
responseView.dismissButton.addTarget(self, action: #selector(dismissSelf), for: .touchUpInside)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,12 @@ final class WalletInteractor {
func disconnectSession(session: Session) async throws {
try await Web3Wallet.instance.disconnect(topic: session.topic)
}

func getPendingProposals() -> [(proposal: Session.Proposal, context: VerifyContext?)] {
Web3Wallet.instance.getPendingProposals()
}

func getPendingRequests() -> [(request: Request, context: VerifyContext?)] {
Web3Wallet.instance.getPendingRequests()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ final class WalletPresenter: ObservableObject {
func onAppear() {
showPairingLoading = app.requestSent
removePairingIndicator()

let proposals = interactor.getPendingProposals()
if let proposal = proposals.last {
router.present(sessionProposal: proposal.proposal, importAccount: importAccount, sessionContext: proposal.context)
}

let pendingRequests = interactor.getPendingRequests()
if let request = pendingRequests.first(where: { $0.context != nil }) {
router.present(sessionRequest: request.request, importAccount: importAccount, sessionContext: request.context)
}
}

func onConnection(session: Session) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ final class WalletRouter {
.presentFullScreen(from: viewController, transparentBackground: true)
}

func present(sessionProposal: Session.Proposal, importAccount: ImportAccount, sessionContext: VerifyContext?) {
SessionProposalModule.create(app: app, importAccount: importAccount, proposal: sessionProposal, context: sessionContext)
.presentFullScreen(from: viewController, transparentBackground: true)
}

func presentPaste(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) {
PasteUriModule.create(app: app, onValue: onValue, onError: onError)
.presentFullScreen(from: viewController, transparentBackground: true)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public class AuthClient: AuthClientProtocol {

/// Query pending authentication requests
/// - Returns: Pending authentication requests
public func getPendingRequests() throws -> [AuthRequest] {
public func getPendingRequests() throws -> [(AuthRequest, VerifyContext?)] {
return try pendingRequestsProvider.getPendingRequests()
}

Expand Down
10 changes: 4 additions & 6 deletions Sources/Auth/AuthClientFactory.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import Foundation

public struct AuthClientFactory {

public static func create(
metadata: AppMetadata,
projectId: String,
crypto: CryptoProvider,
networkingClient: NetworkingInteractor,
pairingRegisterer: PairingRegisterer
) -> AuthClient {

let logger = ConsoleLogger(loggingLevel: .off)
let keyValueStorage = UserDefaults.standard
let keychainStorage = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk")
Expand Down Expand Up @@ -39,19 +37,19 @@ public struct AuthClientFactory {
pairingRegisterer: PairingRegisterer,
iatProvider: IATProvider
) -> AuthClient {

let kms = KeyManagementService(keychain: keychainStorage)
let history = RPCHistoryFactory.createForNetwork(keyValueStorage: keyValueStorage)
let messageFormatter = SIWECacaoFormatter()
let appRequestService = AppRequestService(networkingInteractor: networkingClient, kms: kms, appMetadata: metadata, logger: logger, iatProvader: iatProvider)
let verifyClient = VerifyClientFactory.create()
let verifyContextStore = CodableStore<VerifyContext>(defaults: keyValueStorage, identifier: VerifyStorageIdentifiers.context.rawValue)
let messageVerifierFactory = MessageVerifierFactory(crypto: crypto)
let signatureVerifier = messageVerifierFactory.create(projectId: projectId)
let appRespondSubscriber = AppRespondSubscriber(networkingInteractor: networkingClient, logger: logger, rpcHistory: history, signatureVerifier: signatureVerifier, pairingRegisterer: pairingRegisterer, messageFormatter: messageFormatter)
let walletErrorResponder = WalletErrorResponder(networkingInteractor: networkingClient, logger: logger, kms: kms, rpcHistory: history)
let walletRequestSubscriber = WalletRequestSubscriber(networkingInteractor: networkingClient, logger: logger, kms: kms, walletErrorResponder: walletErrorResponder, pairingRegisterer: pairingRegisterer, verifyClient: verifyClient)
let walletRespondService = WalletRespondService(networkingInteractor: networkingClient, logger: logger, kms: kms, rpcHistory: history, walletErrorResponder: walletErrorResponder)
let pendingRequestsProvider = PendingRequestsProvider(rpcHistory: history)
let walletRequestSubscriber = WalletRequestSubscriber(networkingInteractor: networkingClient, logger: logger, kms: kms, walletErrorResponder: walletErrorResponder, pairingRegisterer: pairingRegisterer, verifyClient: verifyClient, verifyContextStore: verifyContextStore)
let walletRespondService = WalletRespondService(networkingInteractor: networkingClient, logger: logger, kms: kms, rpcHistory: history, verifyContextStore: verifyContextStore, walletErrorResponder: walletErrorResponder)
let pendingRequestsProvider = PendingRequestsProvider(rpcHistory: history, verifyContextStore: verifyContextStore)

return AuthClient(
appRequestService: appRequestService,
Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/AuthClientProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ public protocol AuthClientProtocol {
func formatMessage(payload: AuthPayload, address: String) throws -> String
func respond(requestId: RPCID, signature: CacaoSignature, from account: Account) async throws
func reject(requestId: RPCID) async throws
func getPendingRequests() throws -> [AuthRequest]
func getPendingRequests() throws -> [(AuthRequest, VerifyContext?)]
}
12 changes: 9 additions & 3 deletions Sources/Auth/Services/Wallet/PendingRequestsProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ import Foundation

class PendingRequestsProvider {
private let rpcHistory: RPCHistory
private let verifyContextStore: CodableStore<VerifyContext>

init(rpcHistory: RPCHistory) {
init(
rpcHistory: RPCHistory,
verifyContextStore: CodableStore<VerifyContext>
) {
self.rpcHistory = rpcHistory
self.verifyContextStore = verifyContextStore
}

public func getPendingRequests() throws -> [AuthRequest] {
public func getPendingRequests() throws -> [(AuthRequest, VerifyContext?)] {
let pendingRequests: [AuthRequest] = rpcHistory.getPending()
.filter {$0.request.method == "wc_authRequest"}
.compactMap {
guard let params = try? $0.request.params?.get(AuthRequestParams.self) else { return nil }
return AuthRequest(id: $0.request.id!, topic: $0.topic, payload: params.payloadParams)
}
return pendingRequests

return pendingRequests.map { ($0, try? verifyContextStore.get(key: $0.id.string)) }
}
}
8 changes: 7 additions & 1 deletion Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class WalletRequestSubscriber {
private let walletErrorResponder: WalletErrorResponder
private let pairingRegisterer: PairingRegisterer
private let verifyClient: VerifyClientProtocol
private let verifyContextStore: CodableStore<VerifyContext>

var onRequest: (((request: AuthRequest, context: VerifyContext?)) -> Void)?

init(
Expand All @@ -17,14 +19,16 @@ class WalletRequestSubscriber {
kms: KeyManagementServiceProtocol,
walletErrorResponder: WalletErrorResponder,
pairingRegisterer: PairingRegisterer,
verifyClient: VerifyClientProtocol
verifyClient: VerifyClientProtocol,
verifyContextStore: CodableStore<VerifyContext>
) {
self.networkingInteractor = networkingInteractor
self.logger = logger
self.kms = kms
self.walletErrorResponder = walletErrorResponder
self.pairingRegisterer = pairingRegisterer
self.verifyClient = verifyClient
self.verifyContextStore = verifyContextStore
subscribeForRequest()
}

Expand All @@ -45,9 +49,11 @@ class WalletRequestSubscriber {
do {
let origin = try await verifyClient.verifyOrigin(assertionId: assertionId)
let verifyContext = verifyClient.createVerifyContext(origin: origin, domain: payload.request.payloadParams.domain)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onRequest?((request, verifyContext))
} catch {
let verifyContext = verifyClient.createVerifyContext(origin: nil, domain: payload.request.payloadParams.domain)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onRequest?((request, verifyContext))
return
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/Auth/Services/Wallet/WalletRespondService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ actor WalletRespondService {
private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementService
private let rpcHistory: RPCHistory
private let verifyContextStore: CodableStore<VerifyContext>
private let logger: ConsoleLogging
private let walletErrorResponder: WalletErrorResponder

init(networkingInteractor: NetworkInteracting,
logger: ConsoleLogging,
kms: KeyManagementService,
rpcHistory: RPCHistory,
verifyContextStore: CodableStore<VerifyContext>,
walletErrorResponder: WalletErrorResponder) {
self.networkingInteractor = networkingInteractor
self.logger = logger
self.kms = kms
self.rpcHistory = rpcHistory
self.verifyContextStore = verifyContextStore
self.walletErrorResponder = walletErrorResponder
}

Expand All @@ -35,10 +38,12 @@ actor WalletRespondService {

let response = RPCResponse(id: requestId, result: responseParams)
try await networkingInteractor.respond(topic: topic, response: response, protocolMethod: AuthRequestProtocolMethod(), envelopeType: .type1(pubKey: keys.publicKey.rawRepresentation))
verifyContextStore.delete(forKey: requestId.string)
}

func respondError(requestId: RPCID) async throws {
try await walletErrorResponder.respondError(AuthError.userRejeted, requestId: requestId)
verifyContextStore.delete(forKey: requestId.string)
}

private func getAuthRequestParams(requestId: RPCID) throws -> AuthRequestParams {
Expand Down
6 changes: 6 additions & 0 deletions Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ final class ApproveEngine {
private let sessionStore: WCSessionStorage
private let verifyClient: VerifyClientProtocol
private let proposalPayloadsStore: CodableStore<RequestSubscriptionPayload<SessionType.ProposeParams>>
private let verifyContextStore: CodableStore<VerifyContext>
private let sessionTopicToProposal: CodableStore<Session.Proposal>
private let pairingRegisterer: PairingRegisterer
private let metadata: AppMetadata
Expand All @@ -31,6 +32,7 @@ final class ApproveEngine {
init(
networkingInteractor: NetworkInteracting,
proposalPayloadsStore: CodableStore<RequestSubscriptionPayload<SessionType.ProposeParams>>,
verifyContextStore: CodableStore<VerifyContext>,
sessionTopicToProposal: CodableStore<Session.Proposal>,
pairingRegisterer: PairingRegisterer,
metadata: AppMetadata,
Expand All @@ -42,6 +44,7 @@ final class ApproveEngine {
) {
self.networkingInteractor = networkingInteractor
self.proposalPayloadsStore = proposalPayloadsStore
self.verifyContextStore = verifyContextStore
self.sessionTopicToProposal = sessionTopicToProposal
self.pairingRegisterer = pairingRegisterer
self.metadata = metadata
Expand All @@ -65,6 +68,7 @@ final class ApproveEngine {
let pairingTopic = payload.topic

proposalPayloadsStore.delete(forKey: proposerPubKey)
verifyContextStore.delete(forKey: proposerPubKey)

try Namespace.validate(sessionNamespaces)
try Namespace.validateApproved(sessionNamespaces, against: proposal.requiredNamespaces)
Expand Down Expand Up @@ -113,6 +117,7 @@ final class ApproveEngine {
throw Errors.proposalPayloadsNotFound
}
proposalPayloadsStore.delete(forKey: proposerPubKey)
verifyContextStore.delete(forKey: proposerPubKey)
try await networkingInteractor.respondError(topic: payload.topic, requestId: payload.id, protocolMethod: SessionProposeProtocolMethod(), reason: reason)
// TODO: Delete pairing if inactive
}
Expand Down Expand Up @@ -301,6 +306,7 @@ private extension ApproveEngine {
origin: origin,
domain: payload.request.proposer.metadata.url
)
verifyContextStore.set(verifyContext, forKey: proposal.proposer.publicKey)
onSessionProposal?(proposal.publicRepresentation(pairingTopic: payload.topic), verifyContext)
} catch {
let verifyContext = verifyClient.createVerifyContext(origin: nil, domain: payload.request.proposer.metadata.url)
Expand Down
9 changes: 8 additions & 1 deletion Sources/WalletConnectSign/Engine/Common/SessionEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ final class SessionEngine {
private let sessionStore: WCSessionStorage
private let networkingInteractor: NetworkInteracting
private let historyService: HistoryService
private let verifyContextStore: CodableStore<VerifyContext>
private let verifyClient: VerifyClientProtocol
private let kms: KeyManagementServiceProtocol
private var publishers = [AnyCancellable]()
Expand All @@ -25,13 +26,15 @@ final class SessionEngine {
init(
networkingInteractor: NetworkInteracting,
historyService: HistoryService,
verifyContextStore: CodableStore<VerifyContext>,
verifyClient: VerifyClientProtocol,
kms: KeyManagementServiceProtocol,
sessionStore: WCSessionStorage,
logger: ConsoleLogging
) {
self.networkingInteractor = networkingInteractor
self.historyService = historyService
self.verifyContextStore = verifyContextStore
self.verifyClient = verifyClient
self.kms = kms
self.sessionStore = sessionStore
Expand Down Expand Up @@ -82,6 +85,7 @@ final class SessionEngine {
protocolMethod: protocolMethod,
reason: SignReasonCode.sessionRequestExpired
)
verifyContextStore.delete(forKey: requestId.string)
throw Errors.sessionRequestExpired
}

Expand All @@ -90,6 +94,7 @@ final class SessionEngine {
response: RPCResponse(id: requestId, outcome: response),
protocolMethod: protocolMethod
)
verifyContextStore.delete(forKey: requestId.string)
}

func emit(topic: String, event: SessionType.EventParams.Event, chainId: Blockchain) async throws {
Expand Down Expand Up @@ -185,7 +190,7 @@ private extension SessionEngine {
}

func sessionRequestNotExpired(requestId: RPCID) -> Bool {
guard let request = historyService.getSessionRequest(id: requestId)
guard let request = historyService.getSessionRequest(id: requestId)?.request
else { return false }

return !request.isExpired()
Expand Down Expand Up @@ -243,9 +248,11 @@ private extension SessionEngine {
do {
let origin = try await verifyClient.verifyOrigin(assertionId: assertionId)
let verifyContext = verifyClient.createVerifyContext(origin: origin, domain: session.peerParticipant.metadata.url)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onSessionRequest?(request, verifyContext)
} catch {
let verifyContext = verifyClient.createVerifyContext(origin: nil, domain: session.peerParticipant.metadata.url)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onSessionRequest?(request, verifyContext)
return
}
Expand Down
Loading

0 comments on commit ff1dbbc

Please sign in to comment.