Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[W3W] Add pending proposals #839

Merged
merged 17 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
12 changes: 6 additions & 6 deletions Sources/Auth/AuthClientFactory.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Foundation

public struct AuthClientFactory {
import WalletConnectVerify
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will brake cocoapods


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 +39,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)) }
}
}
9 changes: 7 additions & 2 deletions 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 @@ -44,10 +48,11 @@ class WalletRequestSubscriber {
let assertionId = payload.decryptedPayload.sha256().toHexString()
do {
let origin = try await verifyClient.verifyOrigin(assertionId: assertionId)
let verifyContext = await verifyClient.createVerifyContext(
let verifyContext = verifyClient.createVerifyContext(
origin: origin,
domain: payload.request.payloadParams.domain
)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onRequest?((request, verifyContext))
} catch {
onRequest?((request, nil))
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
8 changes: 7 additions & 1 deletion 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 @@ -297,10 +302,11 @@ private extension ApproveEngine {
let assertionId = payload.decryptedPayload.sha256().toHexString()
do {
let origin = try await verifyClient.verifyOrigin(assertionId: assertionId)
let verifyContext = await verifyClient.createVerifyContext(
let verifyContext = verifyClient.createVerifyContext(
origin: origin,
domain: payload.request.proposer.metadata.url
)
verifyContextStore.set(verifyContext, forKey: proposal.proposer.publicKey)
onSessionProposal?(proposal.publicRepresentation(pairingTopic: payload.topic), verifyContext)
} catch {
onSessionProposal?(proposal.publicRepresentation(pairingTopic: payload.topic), nil)
Expand Down
10 changes: 8 additions & 2 deletions 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 @@ -242,10 +247,11 @@ private extension SessionEngine {
let assertionId = payload.decryptedPayload.sha256().toHexString()
do {
let origin = try await verifyClient.verifyOrigin(assertionId: assertionId)
let verifyContext = await verifyClient.createVerifyContext(
let verifyContext = verifyClient.createVerifyContext(
origin: origin,
domain: session.peerParticipant.metadata.url
)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onSessionRequest?(request, verifyContext)
} catch {
onSessionRequest?(request, nil)
Expand Down
Loading