Skip to content

Commit

Permalink
Merge pull request #342 from WalletConnect/bugfix/#340-required-names…
Browse files Browse the repository at this point in the history
…paces

[Bugfix] #340: Required namespaces check
  • Loading branch information
llbartekll authored Jul 15, 2022
2 parents 77114f9 + 905d49f commit ac6a91c
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 28 deletions.
2 changes: 2 additions & 0 deletions Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ final class ApproveEngine {
selfParticipant: selfParticipant,
peerParticipant: proposal.proposer,
settleParams: settleParams,
requiredNamespaces: proposal.requiredNamespaces,
acknowledged: false)

logger.debug("Sending session settle request")
Expand Down Expand Up @@ -310,6 +311,7 @@ private extension ApproveEngine {
selfParticipant: selfParticipant,
peerParticipant: settleParams.controller,
settleParams: settleParams,
requiredNamespaces: proposedNamespaces,
acknowledged: true
)
sessionStore.setSession(session)
Expand Down
22 changes: 18 additions & 4 deletions Sources/WalletConnectSign/Namespace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ public struct SessionNamespace: Equatable, Codable {
self.events = events
}

func isSuperset(of other: Extension) -> Bool {
self.accounts.isSuperset(of: other.accounts) &&
self.methods.isSuperset(of: other.methods) &&
self.events.isSuperset(of: other.events)
func isCompliant(to required: ProposalNamespace.Extension) -> Bool {
guard
SessionNamespace.accountsAreCompliant(accounts, toChains: required.chains),
methods.isSuperset(of: required.methods),
events.isSuperset(of: required.events)
else {
return false
}
return true
}
}

Expand All @@ -58,6 +63,15 @@ public struct SessionNamespace: Equatable, Codable {
self.events = events
self.extensions = extensions
}

static func accountsAreCompliant(_ accounts: Set<Account>, toChains chains: Set<Blockchain>) -> Bool {
for chain in chains {
guard accounts.contains(where: { $0.blockchain == chain }) else {
return false
}
}
return true
}
}

enum Namespace {
Expand Down
28 changes: 21 additions & 7 deletions Sources/WalletConnectSign/Types/Session/WCSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct WCSession: SequenceObject, Equatable {
private(set) var expiryDate: Date
private(set) var timestamp: Date
private(set) var namespaces: [String: SessionNamespace]
private(set) var requiredNamespaces: [String: SessionNamespace]
private(set) var requiredNamespaces: [String: ProposalNamespace]

static var defaultTimeToLive: Int64 {
Int64(7*Time.day)
Expand All @@ -33,6 +33,7 @@ struct WCSession: SequenceObject, Equatable {
selfParticipant: Participant,
peerParticipant: Participant,
settleParams: SessionType.SettleParams,
requiredNamespaces: [String: ProposalNamespace],
acknowledged: Bool) {
self.topic = topic
self.timestamp = timestamp
Expand All @@ -41,21 +42,34 @@ struct WCSession: SequenceObject, Equatable {
self.selfParticipant = selfParticipant
self.peerParticipant = peerParticipant
self.namespaces = settleParams.namespaces
self.requiredNamespaces = settleParams.namespaces
self.requiredNamespaces = requiredNamespaces
self.acknowledged = acknowledged
self.expiryDate = Date(timeIntervalSince1970: TimeInterval(settleParams.expiry))
}

#if DEBUG
internal init(topic: String, timestamp: Date, relay: RelayProtocolOptions, controller: AgreementPeer, selfParticipant: Participant, peerParticipant: Participant, namespaces: [String: SessionNamespace], events: Set<String>, accounts: Set<Account>, acknowledged: Bool, expiry: Int64) {
internal init(
topic: String,
timestamp: Date,
relay: RelayProtocolOptions,
controller: AgreementPeer,
selfParticipant: Participant,
peerParticipant: Participant,
namespaces: [String: SessionNamespace],
requiredNamespaces: [String: ProposalNamespace],
events: Set<String>,
accounts: Set<Account>,
acknowledged: Bool,
expiry: Int64
) {
self.topic = topic
self.timestamp = timestamp
self.relay = relay
self.controller = controller
self.selfParticipant = selfParticipant
self.peerParticipant = peerParticipant
self.namespaces = namespaces
self.requiredNamespaces = namespaces
self.requiredNamespaces = requiredNamespaces
self.acknowledged = acknowledged
self.expiryDate = Date(timeIntervalSince1970: TimeInterval(expiry))
}
Expand Down Expand Up @@ -121,7 +135,7 @@ struct WCSession: SequenceObject, Equatable {
for item in requiredNamespaces {
guard
let compliantNamespace = namespaces[item.key],
compliantNamespace.accounts.isSuperset(of: item.value.accounts),
SessionNamespace.accountsAreCompliant(compliantNamespace.accounts, toChains: item.value.chains),
compliantNamespace.methods.isSuperset(of: item.value.methods),
compliantNamespace.events.isSuperset(of: item.value.events)
else {
Expand All @@ -132,7 +146,7 @@ struct WCSession: SequenceObject, Equatable {
throw Error.unsatisfiedUpdateNamespaceRequirement
}
for existingExtension in extensions {
guard compliantExtensions.contains(where: { $0.isSuperset(of: existingExtension) }) else {
guard compliantExtensions.contains(where: { $0.isCompliant(to: existingExtension) }) else {
throw Error.unsatisfiedUpdateNamespaceRequirement
}
}
Expand Down Expand Up @@ -194,7 +208,7 @@ extension WCSession {

// Migration beta.102
self.timestamp = try container.decodeIfPresent(Date.self, forKey: .timestamp) ?? .distantPast
self.requiredNamespaces = try container.decodeIfPresent([String: SessionNamespace].self, forKey: .requiredNamespaces) ?? [:]
self.requiredNamespaces = try container.decodeIfPresent([String: ProposalNamespace].self, forKey: .requiredNamespaces) ?? [:]
}

func encode(to encoder: Encoder) throws {
Expand Down
2 changes: 2 additions & 0 deletions Tests/WalletConnectSignTests/Stub/Session+Stub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extension WCSession {
expiryDate: Date = Date.distantFuture,
selfPrivateKey: AgreementPrivateKey = AgreementPrivateKey(),
namespaces: [String: SessionNamespace] = [:],
requiredNamespaces: [String: ProposalNamespace] = [:],
acknowledged: Bool = true,
timestamp: Date = Date()
) -> WCSession {
Expand All @@ -23,6 +24,7 @@ extension WCSession {
selfParticipant: Participant.stub(publicKey: selfKey),
peerParticipant: Participant.stub(publicKey: peerKey),
namespaces: namespaces,
requiredNamespaces: requiredNamespaces,
events: [],
accounts: Account.stubSet(),
acknowledged: acknowledged,
Expand Down
54 changes: 37 additions & 17 deletions Tests/WalletConnectSignTests/WCSessionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,32 +141,40 @@ final class WCSessionTests: XCTestCase {

// MARK: Namespace Update Tests

private func stubRequiredNamespaces() -> [String: SessionNamespace] {
private func stubRequiredNamespaces() -> [String: ProposalNamespace] {
return [
"eip155": SessionNamespace(
accounts: [ethAccount, polyAccount],
"eip155": ProposalNamespace(
chains: [ethAccount.blockchain, polyAccount.blockchain],
methods: ["method", "method-2"],
events: ["event", "event-2"],
extensions: nil)]
}

private func stubRequiredNamespacesWithExtension() -> [String: SessionNamespace] {
private func stubCompliantNamespaces() -> [String: SessionNamespace] {
return [
"eip155": SessionNamespace(
accounts: [ethAccount, polyAccount],
methods: ["method", "method-2"],
events: ["event", "event-2"],
extensions: nil)]
}

private func stubRequiredNamespacesWithExtension() -> [String: ProposalNamespace] {
return [
"eip155": ProposalNamespace(
chains: [ethAccount.blockchain, polyAccount.blockchain],
methods: ["method", "method-2"],
events: ["event", "event-2"],
extensions: [
SessionNamespace.Extension(
accounts: [ethAccount, polyAccount],
ProposalNamespace.Extension(
chains: [ethAccount.blockchain, polyAccount.blockchain],
methods: ["method-2", "newMethod-2"],
events: ["event-2", "newEvent-2"])])]
}

func testUpdateEqualNamespaces() {
let namespace = stubRequiredNamespaces()
var session = WCSession.stub(namespaces: namespace)
XCTAssertNoThrow(try session.updateNamespaces(namespace))
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespaces())
XCTAssertNoThrow(try session.updateNamespaces(stubCompliantNamespaces()))
}

func testUpdateNamespacesOverRequirement() {
Expand Down Expand Up @@ -195,18 +203,30 @@ final class WCSessionTests: XCTestCase {
}

func testUpdateLessThanRequiredChains() {
var session = WCSession.stub(namespaces: stubRequiredNamespaces())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespaces())
XCTAssertThrowsError(try session.updateNamespaces([:]))
}

func testUpdateReplaceAccount() {
let newEthAccount = Account("eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdf")!
let valid = [
"eip155": SessionNamespace(
accounts: [newEthAccount, polyAccount],
methods: ["method", "method-2"],
events: ["event", "event-2"],
extensions: nil)]
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespaces())
XCTAssertNoThrow(try session.updateNamespaces(valid))
}

func testUpdateLessThanRequiredAccounts() {
let invalid = [
"eip155": SessionNamespace(
accounts: [ethAccount],
methods: ["method", "method-2"],
events: ["event", "event-2"],
extensions: nil)]
var session = WCSession.stub(namespaces: stubRequiredNamespaces())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespaces())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}

Expand All @@ -217,7 +237,7 @@ final class WCSessionTests: XCTestCase {
methods: ["method"],
events: ["event", "event-2"],
extensions: nil)]
var session = WCSession.stub(namespaces: stubRequiredNamespaces())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespaces())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}

Expand All @@ -228,7 +248,7 @@ final class WCSessionTests: XCTestCase {
methods: ["method", "method-2"],
events: ["event"],
extensions: nil)]
var session = WCSession.stub(namespaces: stubRequiredNamespaces())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespaces())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}

Expand All @@ -239,7 +259,7 @@ final class WCSessionTests: XCTestCase {
methods: ["method", "method-2"],
events: ["event", "event-2"],
extensions: nil)]
var session = WCSession.stub(namespaces: stubRequiredNamespacesWithExtension())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespacesWithExtension())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}

Expand All @@ -254,7 +274,7 @@ final class WCSessionTests: XCTestCase {
accounts: [ethAccount],
methods: ["method-2", "newMethod-2"],
events: ["event-2", "newEvent-2"])])]
var session = WCSession.stub(namespaces: stubRequiredNamespacesWithExtension())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespacesWithExtension())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}

Expand All @@ -269,7 +289,7 @@ final class WCSessionTests: XCTestCase {
accounts: [ethAccount, polyAccount],
methods: ["method-2"],
events: ["event-2", "newEvent-2"])])]
var session = WCSession.stub(namespaces: stubRequiredNamespacesWithExtension())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespacesWithExtension())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}

Expand All @@ -284,7 +304,7 @@ final class WCSessionTests: XCTestCase {
accounts: [ethAccount, polyAccount],
methods: ["method-2", "newMethod-2"],
events: ["event-2"])])]
var session = WCSession.stub(namespaces: stubRequiredNamespacesWithExtension())
var session = WCSession.stub(requiredNamespaces: stubRequiredNamespacesWithExtension())
XCTAssertThrowsError(try session.updateNamespaces(invalid))
}
}

0 comments on commit ac6a91c

Please sign in to comment.