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

Autonamespace fix #1305

Merged
merged 9 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
Copy link
Contributor

Choose a reason for hiding this comment

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

upsupportedEvents misspelled word

}

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
Loading