Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:WalletConnect/WalletConnectSwift…
Browse files Browse the repository at this point in the history
…V2 into #74-extract-KMS

# Conflicts:
#	Sources/WalletConnect/Engine/PairingEngine.swift
#	Sources/WalletConnect/Engine/SessionEngine.swift
#	Sources/WalletConnect/WalletConnectClient.swift
  • Loading branch information
llbartekll committed Feb 11, 2022
2 parents 885d109 + 0f0f258 commit 14f67f1
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 227 deletions.
2 changes: 1 addition & 1 deletion Example/DApp/ClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ClientDelegate: WalletConnectClientDelegate {
onSessionResponse?(sessionResponse)
}

func didUpdate(sessionTopic: String, accounts: Set<String>) {
func didUpdate(sessionTopic: String, accounts: Set<Account>) {
}

func didUpgrade(sessionTopic: String, permissions: Session.Permissions) {
Expand Down
6 changes: 3 additions & 3 deletions Example/ExampleApp/Responder/ResponderViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ extension ResponderViewController: SessionViewControllerDelegate {
print("[RESPONDER] Approving session...")
let proposal = currentProposal!
currentProposal = nil
let accounts = proposal.permissions.blockchains.map {$0+":\(account)"}
client.approve(proposal: proposal, accounts: Set(accounts))
let accounts = Set(proposal.permissions.blockchains.compactMap { Account($0+":\(account)") })
client.approve(proposal: proposal, accounts: accounts)
}

func didRejectSession() {
Expand Down Expand Up @@ -196,7 +196,7 @@ extension ResponderViewController: WalletConnectClientDelegate {

}

func didUpdate(sessionTopic: String, accounts: Set<String>) {
func didUpdate(sessionTopic: String, accounts: Set<Account>) {

}

Expand Down
94 changes: 94 additions & 0 deletions Sources/WalletConnect/Account.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
A value that identifies an account in any given blockchain.
This structure parses account IDs according to [CAIP-10].
Account IDs are prefixed with a [CAIP-2] blockchain ID, delimited by a `':'` character, followed by the account address.
Specifying a blockchain account by using a chain-agnostic identifier is useful to allow interoperability between multiple
chains when using both wallets and decentralized applications.
[CAIP-2]:https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md
[CAIP-10]:https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md
*/
public struct Account: Equatable, Hashable {

/// A blockchain namespace. Usually describes an ecosystem or standard.
public let namespace: String

/// A reference string that identifies a blockchain within a given namespace.
public let reference: String

/// The account's address specific to the blockchain.
public let address: String

/// The CAIP-2 blockchain identifier of the account.
public var blockchainIdentifier: String {
"\(namespace):\(reference)"
}

/// The CAIP-10 account identifier absolute string.
public var absoluteString: String {
"\(namespace):\(reference):\(address)"
}

/// Returns whether the account conforms to CAIP-10.
public var isCAIP10Conformant: Bool {
String.conformsToCAIP10(absoluteString)
}

/**
Creates an account instance from the provided string.
This initializer returns nil if the string doesn't represent a valid account id in conformance with
[CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md).
*/
public init?(_ string: String) {
guard String.conformsToCAIP10(string) else { return nil }
let splits = string.split(separator: ":")
self.init(namespace: String(splits[0]), reference: String(splits[1]), address: String(splits[2]))
}

/**
Creates an account instance from a chain ID and an address.
This initializer returns nil if the `chainIdentifier` parameter doesn't represent a valid chain id in conformance with
[CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md) or if the `address` format is invalid.
*/
public init?(chainIdentifier: String, address: String) {
self.init("\(chainIdentifier):\(address)")
}

/**
Creates an account instance directly from the base components.
This initializer bypass any checks to CAIP conformance, make sure to pass valid values as parameters.
*/
public init(namespace: String, reference: String, address: String) {
self.namespace = namespace
self.reference = reference
self.address = address
}
}

extension Account: LosslessStringConvertible {
public var description: String {
return absoluteString
}
}

extension Account: Codable {

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let absoluteString = try container.decode(String.self)
guard let account = Account(absoluteString) else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Malformed CAIP-10 account identifier.")
}
self = account
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(absoluteString)
}
}
131 changes: 54 additions & 77 deletions Sources/WalletConnect/Engine/PairingEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,76 +163,25 @@ final class PairingEngine {

private func setUpWCRequestHandling() {
wcSubscriber.onReceivePayload = { [unowned self] subscriptionPayload in
let requestId = subscriptionPayload.wcRequest.id
let topic = subscriptionPayload.topic
switch subscriptionPayload.wcRequest.params {
case .pairingApprove(let approveParams):
handlePairingApprove(approveParams: approveParams, pendingPairingTopic: topic, requestId: requestId)
wcPairingApprove(subscriptionPayload, approveParams: approveParams)
case .pairingUpdate(let updateParams):
handlePairingUpdate(params: updateParams, topic: topic, requestId: requestId)
wcPairingUpdate(subscriptionPayload, updateParams: updateParams)
case .pairingPayload(let pairingPayload):
self.handlePairingPayload(pairingPayload, for: topic, requestId: requestId)
wcPairingPayload(subscriptionPayload, payloadParams: pairingPayload)
case .pairingPing(_):
self.handlePairingPing(topic: topic, requestId: requestId)
wcPairingPing(subscriptionPayload)
default:
logger.warn("Warning: Pairing Engine - Unexpected method type: \(subscriptionPayload.wcRequest.method) received from subscriber")
}
}
}

private func handlePairingUpdate(params: PairingType.UpdateParams,topic: String, requestId: Int64) {
guard var pairing = try? sequencesStore.getSequence(forTopic: topic) else {
logger.debug("Could not find pairing for topic \(topic)")
return
}
guard pairing.peerIsController else {
let error = WalletConnectError.unauthrorized(.unauthorizedUpdateRequest)
logger.error(error)
respond(error: error, requestId: requestId, topic: topic)
return
}
let response = JSONRPCResponse<AnyCodable>(id: requestId, result: AnyCodable(true))
relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { [unowned self] error in
if let error = error {
logger.error(error)
} else {
pairing.settled?.state = params.state
sequencesStore.setSequence(pairing)
onPairingUpdate?(topic, params.state.metadata)
}
}
}

private func handlePairingPing(topic: String, requestId: Int64) {
let response = JSONRPCResponse<AnyCodable>(id: requestId, result: AnyCodable(true))
relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { error in
//todo
}
}

private func handlePairingPayload(_ payload: PairingType.PayloadParams, for topic: String, requestId: Int64) {
logger.debug("Will handle pairing payload")
guard sequencesStore.hasSequence(forTopic: topic) else {
logger.error("Pairing for the topic: \(topic) does not exist")
return
}
guard payload.request.method == PairingType.PayloadMethods.sessionPropose else {
logger.error("Forbidden WCPairingPayload method")
return
}
let sessionProposal = payload.request.params
if let pairingAgreementSecret = try? kms.getAgreementSecret(for: sessionProposal.signal.params.topic) {
try? kms.setAgreementSecret(pairingAgreementSecret, topic: sessionProposal.topic)
}
let response = JSONRPCResponse<AnyCodable>(id: requestId, result: AnyCodable(true))
relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { [weak self] error in
self?.onSessionProposal?(sessionProposal)
}
}

private func handlePairingApprove(approveParams: PairingType.ApprovalParams, pendingPairingTopic: String, requestId: Int64) {
logger.debug("Responder Client approved pairing on topic: \(pendingPairingTopic)")
private func wcPairingApprove(_ payload: WCRequestSubscriptionPayload, approveParams: PairingType.ApprovalParams) {
let pendingPairingTopic = payload.topic
guard let pairing = try? sequencesStore.getSequence(forTopic: pendingPairingTopic), let pendingPairing = pairing.pending else {
relayer.respondError(for: payload, reason: .noContextWithTopic(context: .pairing, topic: pendingPairingTopic))
return
}

Expand All @@ -254,15 +203,55 @@ final class PairingEngine {
}
sessionPermissions[pendingPairingTopic] = nil

// TODO: Move JSON-RPC responding to networking layer
let response = JSONRPCResponse<AnyCodable>(id: requestId, result: AnyCodable(true))
relayer.respond(topic: proposal.topic, response: JsonRpcResult.response(response)) { [weak self] error in
if let error = error {
self?.logger.error("Could not respond with error: \(error)")
}
relayer.respondSuccess(for: payload)
onPairingApproved?(Pairing(topic: settledPairing.topic, peer: nil), permissions, settledPairing.relay)
}

private func wcPairingUpdate(_ payload: WCRequestSubscriptionPayload, updateParams: PairingType.UpdateParams) {
let topic = payload.topic
guard var pairing = try? sequencesStore.getSequence(forTopic: topic) else {
relayer.respondError(for: payload, reason: .noContextWithTopic(context: .pairing, topic: topic))
return
}
guard pairing.peerIsController else {
relayer.respondError(for: payload, reason: .unauthorizedUpdateRequest(context: .pairing))
return
}

onPairingApproved?(Pairing(topic: settledPairing.topic, peer: nil), permissions, settledPairing.relay)
pairing.settled?.state = updateParams.state
sequencesStore.setSequence(pairing)

relayer.respondSuccess(for: payload)
onPairingUpdate?(topic, updateParams.state.metadata)
}

private func wcPairingPayload(_ payload: WCRequestSubscriptionPayload, payloadParams: PairingType.PayloadParams) {
guard sequencesStore.hasSequence(forTopic: payload.topic) else {
relayer.respondError(for: payload, reason: .noContextWithTopic(context: .pairing, topic: payload.topic))
return
}
guard payloadParams.request.method == PairingType.PayloadMethods.sessionPropose else {
relayer.respondError(for: payload, reason: .unauthorizedRPCMethod(payloadParams.request.method.rawValue))
return
}
let sessionProposal = payloadParams.request.params
do {
if let pairingAgreementSecret = try kms.getAgreementSecret(for: sessionProposal.signal.params.topic) {
try kms.setAgreementSecret(pairingAgreementSecret, topic: sessionProposal.topic)
} else {
relayer.respondError(for: payload, reason: .missingOrInvalid("agreement keys"))
return
}
} catch {
relayer.respondError(for: payload, reason: .missingOrInvalid("agreement keys"))
return
}
relayer.respondSuccess(for: payload)
onSessionProposal?(sessionProposal)
}

private func wcPairingPing(_ payload: WCRequestSubscriptionPayload) {
relayer.respondSuccess(for: payload)
}

private func removeRespondedPendingPairings() {
Expand All @@ -289,18 +278,6 @@ final class PairingEngine {
}
}

private func respond(error: WalletConnectError, requestId: Int64, topic: String) {
let jsonrpcError = JSONRPCErrorResponse.Error(code: error.code, message: error.description)
let response = JSONRPCErrorResponse(id: requestId, error: jsonrpcError)
relayer.respond(topic: topic, response: .error(response)) { [weak self] responseError in
if let responseError = responseError {
self?.logger.error("Could not respond with error: \(responseError)")
} else {
self?.logger.debug("successfully responded with error")
}
}
}

private func handleReponse(_ response: WCResponse) {
switch response.requestParams {
case .pairingApprove:
Expand Down
Loading

0 comments on commit 14f67f1

Please sign in to comment.