Skip to content

Commit

Permalink
Merge pull request #1305 from WalletConnect/autonamespace-fix
Browse files Browse the repository at this point in the history
Autonamespace fix
  • Loading branch information
llbartekll authored Feb 14, 2024
2 parents 853bca5 + 731b74c commit c0849b0
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 248 deletions.
46 changes: 23 additions & 23 deletions Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,29 +245,29 @@ final class NotifyTests: XCTestCase {
}
}

func testFetchHistory() async throws {
let subscribeExpectation = expectation(description: "fetch notify subscription")
let account = Account("eip155:1:0x622b17376F76d72C43527a917f59273247A917b4")!

var subscription: NotifySubscription!
walletNotifyClientA.subscriptionsPublisher
.sink { subscriptions in
subscription = subscriptions.first
subscribeExpectation.fulfill()
}.store(in: &publishers)

try await walletNotifyClientA.register(account: account, domain: gmDappDomain) { message in
let privateKey = Data(hex: "c3ff8a0ae33ac5d58e515055c5870fa2f220d070997bd6fd77a5f2c148528ff0")
let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId)
return try! signer.sign(message: message, privateKey: privateKey, type: .eip191)
}

await fulfillment(of: [subscribeExpectation], timeout: InputConfig.defaultTimeout)

let hasMore = try await walletNotifyClientA.fetchHistory(subscription: subscription, after: nil, limit: 20)
XCTAssertTrue(hasMore)
XCTAssertTrue(walletNotifyClientA.getMessageHistory(topic: subscription.topic).count == 20)
}
// func testFetchHistory() async throws {
// let subscribeExpectation = expectation(description: "fetch notify subscription")
// let account = Account("eip155:1:0x622b17376F76d72C43527a917f59273247A917b4")!
//
// var subscription: NotifySubscription!
// walletNotifyClientA.subscriptionsPublisher
// .sink { subscriptions in
// subscription = subscriptions.first
// subscribeExpectation.fulfill()
// }.store(in: &publishers)
//
// try await walletNotifyClientA.register(account: account, domain: gmDappDomain) { message in
// let privateKey = Data(hex: "c3ff8a0ae33ac5d58e515055c5870fa2f220d070997bd6fd77a5f2c148528ff0")
// let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId)
// return try! signer.sign(message: message, privateKey: privateKey, type: .eip191)
// }
//
// await fulfillment(of: [subscribeExpectation], timeout: InputConfig.defaultTimeout)
//
// let hasMore = try await walletNotifyClientA.fetchHistory(subscription: subscription, after: nil, limit: 20)
// XCTAssertTrue(hasMore)
// XCTAssertTrue(walletNotifyClientA.getMessageHistory(topic: subscription.topic).count == 20)
// }
}


Expand Down
4 changes: 2 additions & 2 deletions Example/IntegrationTests/Sign/SignClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ final class SignClientTests: XCTestCase {
wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in
Task(priority: .high) {
do {
try await wallet.reject(proposalId: proposal.id, reason: .userRejectedChains) // TODO: Review reason
try await wallet.reject(proposalId: proposal.id, reason: .unsupportedChains)
store.rejectedProposal = proposal
semaphore.signal()
} catch { XCTFail("\(error)") }
Expand All @@ -119,7 +119,7 @@ final class SignClientTests: XCTestCase {
dapp.sessionRejectionPublisher.sink { proposal, _ in
semaphore.wait()
XCTAssertEqual(store.rejectedProposal, proposal)
sessionRejectExpectation.fulfill() // TODO: Assert reason code
sessionRejectExpectation.fulfill()
}.store(in: &publishers)
await fulfillment(of: [sessionRejectExpectation], timeout: InputConfig.defaultTimeout)
}
Expand Down
2 changes: 1 addition & 1 deletion Example/Shared/Signer/SOLSigner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct SOLSigner {
return account.publicKey.base58EncodedString
}

private static let account: Account = {
static let account: Account = {
let key = "4eN1YZm598FtdigriE5int7Gf5dxs58rzVh3ftRwxjkYXxkiDiweuvkop2Kr5Td174DcbVdDxzjWqQ96uir3NYka"
return try! Account(secretKey: Data(Base58.decode(key)))
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,35 @@ final class SessionProposalInteractor {

let supportedRequiredChains = proposal.requiredNamespaces["eip155"]?.chains
let supportedOptionalChains = proposal.optionalNamespaces?["eip155"]?.chains ?? []
let supportedChains = (supportedRequiredChains ?? []).union(supportedOptionalChains) ?? []
var supportedChains = (supportedRequiredChains ?? []).union(supportedOptionalChains)

let supportedAccounts = Array(supportedChains).map { Account(blockchain: $0, address: account.address)! }

/* Use only supported values for production. I.e:
let supportedMethods = ["eth_signTransaction", "personal_sign", "eth_signTypedData", "eth_sendTransaction", "eth_sign"]
let supportedEvents = ["accountsChanged", "chainChanged"]
let supportedChains = [Blockchain("eip155:1")!, Blockchain("eip155:137")!]
let supportedAccounts = [Account(blockchain: Blockchain("eip155:1")!, address: ETHSigner.address)!, Account(blockchain: Blockchain("eip155:137")!, address: ETHSigner.address)!]
*/
let sessionNamespaces = try AutoNamespaces.build(
sessionProposal: proposal,
chains: Array(supportedChains),
methods: Array(supportedMethods),
events: Array(supportedEvents),
accounts: supportedAccounts
)
var sessionNamespaces: [String: SessionNamespace]!

do {
sessionNamespaces = try AutoNamespaces.build(
sessionProposal: proposal,
chains: Array(supportedChains),
methods: Array(supportedMethods),
events: Array(supportedEvents),
accounts: supportedAccounts
)
} catch let error as AutoNamespacesError {
try await reject(proposal: proposal, reason: RejectionReason(from: error))
AlertPresenter.present(message: error.localizedDescription, type: .error)
return false
} catch {
try await reject(proposal: proposal, reason: .userRejected)
AlertPresenter.present(message: error.localizedDescription, type: .error)
return false
}
try await Web3Wallet.instance.approve(proposalId: proposal.id, namespaces: sessionNamespaces, sessionProperties: proposal.sessionProperties)

if let uri = proposal.proposer.redirect?.native {
Expand All @@ -38,7 +50,7 @@ final class SessionProposalInteractor {
}
}

func reject(proposal: Session.Proposal) async throws {
func reject(proposal: Session.Proposal, reason: RejectionReason = .userRejected) async throws {
try await Web3Wallet.instance.reject(proposalId: proposal.id, reason: .userRejected)

/* Redirect */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ private extension SessionEngine {
}

func onSessionRequest(payload: RequestSubscriptionPayload<SessionType.RequestParams>) {
logger.debug("Received session request")
let protocolMethod = SessionRequestProtocolMethod()
let topic = payload.topic
let request = Request(
Expand Down
11 changes: 6 additions & 5 deletions Sources/WalletConnectSign/Namespace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public enum AutoNamespacesError: Error, LocalizedError {
case requiredAccountsNotSatisfied
case requiredMethodsNotSatisfied
case requiredEventsNotSatisfied
case emtySessionNamespacesForbidden
case emptySessionNamespacesForbidden

public var errorDescription: String? {
switch self {
Expand All @@ -17,7 +17,7 @@ public enum AutoNamespacesError: Error, LocalizedError {
return "The required methods are not satisfied."
case .requiredEventsNotSatisfied:
return "The required events are not satisfied."
case .emtySessionNamespacesForbidden:
case .emptySessionNamespacesForbidden:
return "Empty session namespaces are not allowed."
}
}
Expand Down Expand Up @@ -180,8 +180,9 @@ public enum AutoNamespaces {
let proposalNamespace = $0.value

if let proposalChains = proposalNamespace.chains {
let sessionChains = Set(proposalChains).intersection(Set(chains))
guard !sessionChains.isEmpty else {
let sessionChains = proposalChains

guard !sessionChains.isEmpty && proposalChains.isSubset(of: chains) else {
throw AutoNamespacesError.requiredChainsNotSatisfied
}

Expand Down Expand Up @@ -340,7 +341,7 @@ public enum AutoNamespaces {
}
}
}
guard !sessionNamespaces.isEmpty else { throw AutoNamespacesError.emtySessionNamespacesForbidden }
guard !sessionNamespaces.isEmpty else { throw AutoNamespacesError.emptySessionNamespacesForbidden }

return sessionNamespaces
}
Expand Down
34 changes: 27 additions & 7 deletions Sources/WalletConnectSign/RejectionReason.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,42 @@ import Foundation
/// https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md
public enum RejectionReason {
case userRejected
case userRejectedChains
case userRejectedMethods
case userRejectedEvents
case unsupportedChains
case unsupportedMethods
case unsupportedAccounts
case upsupportedEvents
}

internal extension RejectionReason {
func internalRepresentation() -> SignReasonCode {
switch self {
case .userRejected:
return SignReasonCode.userRejected
case .userRejectedChains:
return SignReasonCode.userRejectedChains
case .userRejectedMethods:
case .unsupportedChains:
return SignReasonCode.unsupportedChains
case .unsupportedMethods:
return SignReasonCode.userRejectedMethods
case .userRejectedEvents:
case .upsupportedEvents:
return SignReasonCode.userRejectedEvents
case .unsupportedAccounts:
return SignReasonCode.unsupportedAccounts
}
}
}

public extension RejectionReason {
init(from error: AutoNamespacesError) {
switch error {
case .requiredChainsNotSatisfied:
self = .unsupportedChains
case .requiredAccountsNotSatisfied:
self = .unsupportedAccounts
case .requiredMethodsNotSatisfied:
self = .unsupportedMethods
case .requiredEventsNotSatisfied:
self = .upsupportedEvents
case .emptySessionNamespacesForbidden:
self = .unsupportedAccounts
}
}
}
10 changes: 10 additions & 0 deletions Sources/WalletConnectSign/Sign/SessionRequestsProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import Foundation
class SessionRequestsProvider {
private let historyService: HistoryService
private var sessionRequestPublisherSubject = PassthroughSubject<(request: Request, context: VerifyContext?), Never>()
private var lastEmitTime: Date?
private let debounceInterval: TimeInterval = 1

public var sessionRequestPublisher: AnyPublisher<(request: Request, context: VerifyContext?), Never> {
sessionRequestPublisherSubject.eraseToAnyPublisher()
}
Expand All @@ -13,6 +16,13 @@ class SessionRequestsProvider {
}

func emitRequestIfPending() {
let now = Date()
if let lastEmitTime = lastEmitTime, now.timeIntervalSince(lastEmitTime) < debounceInterval {
return
}

self.lastEmitTime = now

if let oldestRequest = self.historyService.getPendingRequestsSortedByTimestamp().first {
self.sessionRequestPublisherSubject.send(oldestRequest)
}
Expand Down
Loading

0 comments on commit c0849b0

Please sign in to comment.