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

[Push] Add wc_pushPropose method #872

Merged
merged 21 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from 20 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
22 changes: 4 additions & 18 deletions Example/DApp/Sign/Accounts/AccountsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ final class AccountsViewController: UIViewController, UITableViewDataSource, UIT
action: #selector(disconnect)
)

navigationItem.leftBarButtonItem = UIBarButtonItem(
title: "Push Test",
style: .plain,
target: self,
action: #selector(pushTest)
)

accountsView.tableView.dataSource = self
accountsView.tableView.delegate = self
session.namespaces.values.forEach { namespace in
Expand All @@ -65,24 +58,17 @@ final class AccountsViewController: UIViewController, UITableViewDataSource, UIT
func proposePushSubscription() {
let account = session.namespaces.values.first!.accounts.first!

Task(priority: .high){ try! await Push.dapp.request(account: account, topic: session.pairingTopic)}
Push.dapp.responsePublisher.sink { (id: RPCID, result: Result<PushSubscriptionResult, PushError>) in
Task(priority: .high){ try! await Push.dapp.propose(account: account, topic: session.pairingTopic)}
Push.dapp.proposalResponsePublisher.sink { result in
switch result {
case .success(let subscriptionResult):
self.pushSubscription = subscriptionResult.pushSubscription
case .success(let subscription):
self.pushSubscription = subscription
case .failure(let error):
print(error)
}
}.store(in: &publishers)
}

@objc
private func pushTest() {
guard let pushTopic = pushSubscription?.topic else {return}
let message = PushMessage(title: "Push Message", body: "He,y this is a message from the swift client", icon: "", url: "")
Task(priority: .userInitiated) { try! await Push.dapp.notify(topic: pushTopic, message: message) }
}

@objc
private func disconnect() {
Task {
Expand Down
6 changes: 3 additions & 3 deletions Example/IntegrationTests/Pairing/PairingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ final class PairingTests: XCTestCase {

try! await walletPairingClient.pair(uri: uri)

try! await appPushClient.request(account: Account.stub(), topic: uri.topic)
try! await appPushClient.propose(account: Account.stub(), topic: uri.topic)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}
Expand All @@ -129,7 +129,7 @@ final class PairingTests: XCTestCase {
makeWalletPairingClient()
let expectation = expectation(description: "wallet responds unsupported method for unregistered method")

appPushClient.responsePublisher.sink { (_, response) in
appPushClient.proposalResponsePublisher.sink { (response) in
XCTAssertEqual(response, .failure(PushError(code: 10001)!))
expectation.fulfill()
}.store(in: &publishers)
Expand All @@ -138,7 +138,7 @@ final class PairingTests: XCTestCase {

try! await walletPairingClient.pair(uri: uri)

try! await appPushClient.request(account: Account.stub(), topic: uri.topic)
try! await appPushClient.propose(account: Account.stub(), topic: uri.topic)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}
Expand Down
129 changes: 27 additions & 102 deletions Example/IntegrationTests/Push/PushTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ final class PushTests: XCTestCase {
let (pairingClient, networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix)
let pushLogger = ConsoleLogger(suffix: prefix + " [Push]", loggingLevel: .debug)
dappPairingClient = pairingClient
dappPushClient = DappPushClientFactory.create(metadata: AppMetadata(name: name, description: "", url: "", icons: [""]),
dappPushClient = DappPushClientFactory.create(metadata: AppMetadata(name: "GM Dapp", description: "", url: "https://gm-dapp-xi.vercel.app/", icons: []),
logger: pushLogger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
Expand Down Expand Up @@ -91,55 +91,40 @@ final class PushTests: XCTestCase {
makeWalletClients()
}

func testRequestPush() async {
Copy link
Contributor

Choose a reason for hiding this comment

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

push request step removed from protocol right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

exactly, the method is deprecated

let expectation = expectation(description: "expects to receive push request")

let uri = try! await dappPairingClient.create()
try! await walletPairingClient.pair(uri: uri)
try! await dappPushClient.request(account: Account.stub(), topic: uri.topic)

walletPushClient.requestPublisher.sink { (_, _, _) in
expectation.fulfill()
}
.store(in: &publishers)
wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}

func testWalletApprovesPushRequest() async {
let expectation = expectation(description: "expects dapp to receive successful response")
func testPushPropose() async {
let expectation = expectation(description: "expects dapp to receive error response")

let uri = try! await dappPairingClient.create()
try! await walletPairingClient.pair(uri: uri)
try! await dappPushClient.request(account: Account.stub(), topic: uri.topic)
try! await dappPushClient.propose(account: Account.stub(), topic: uri.topic)

walletPushClient.requestPublisher.sink { [unowned self] (id, _, _) in
Task(priority: .high) { try! await walletPushClient.approve(id: id, onSign: sign) }
}.store(in: &publishers)

dappPushClient.responsePublisher.sink { (_, result) in
dappPushClient.proposalResponsePublisher.sink { (result) in
guard case .success = result else {
XCTFail()
return
}
expectation.fulfill()
}.store(in: &publishers)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)

}

func testWalletRejectsPushRequest() async {
func testWalletRejectsPushPropose() async {
let expectation = expectation(description: "expects dapp to receive error response")

let uri = try! await dappPairingClient.create()
try! await walletPairingClient.pair(uri: uri)
try! await dappPushClient.request(account: Account.stub(), topic: uri.topic)
try! await dappPushClient.propose(account: Account.stub(), topic: uri.topic)

walletPushClient.requestPublisher.sink { [unowned self] (id, _, _) in

Task(priority: .high) { try! await walletPushClient.reject(id: id) }
}.store(in: &publishers)

dappPushClient.responsePublisher.sink { (_, result) in
dappPushClient.proposalResponsePublisher.sink { (result) in
guard case .failure = result else {
XCTFail()
return
Expand All @@ -150,108 +135,48 @@ final class PushTests: XCTestCase {
wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}

func testDappSendsPushMessage() async {
let expectation = expectation(description: "expects wallet to receive push message")
let pushMessage = PushMessage.stub()
var pushSubscription: PushSubscription!
let uri = try! await dappPairingClient.create()
try! await walletPairingClient.pair(uri: uri)
try! await dappPushClient.request(account: Account.stub(), topic: uri.topic)

walletPushClient.requestPublisher.sink { [unowned self] (id, _, _) in
Task(priority: .high) { try! await walletPushClient.approve(id: id, onSign: sign) }
}.store(in: &publishers)

dappPushClient.responsePublisher.sink { [unowned self] (_, result) in
guard case .success(let result) = result else {
XCTFail()
return
}
pushSubscription = result.pushSubscription
Task(priority: .userInitiated) { try! await dappPushClient.notify(topic: result.pushSubscription.topic, message: pushMessage) }
}.store(in: &publishers)

walletPushClient.pushMessagePublisher.sink { [unowned self] receivedPushMessageRecord in
let messageHistory = walletPushClient.getMessageHistory(topic: pushSubscription.topic)
XCTAssertEqual(pushMessage, receivedPushMessageRecord.message)
XCTAssertTrue(messageHistory.contains(receivedPushMessageRecord))
expectation.fulfill()
}.store(in: &publishers)


func testWalletCreatesSubscription() async {
let expectation = expectation(description: "expects to create push subscription")
let metadata = AppMetadata(name: "GM Dapp", description: "", url: "https://gm-dapp-xi.vercel.app/", icons: [])
try! await walletPushClient.subscribe(metadata: metadata, account: Account.stub(), onSign: sign)
walletPushClient.subscriptionsPublisher
.first()
Copy link
Contributor

Choose a reason for hiding this comment

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

why first here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

because after calling deleteSubscription, subscriptionsPublisher will publish again with an empty array

.sink { [unowned self] subscriptions in
XCTAssertNotNil(subscriptions.first)
Task { try! await walletPushClient.deleteSubscription(topic: subscriptions.first!.topic) }
expectation.fulfill()
}.store(in: &publishers)
wait(for: [expectation], timeout: InputConfig.defaultTimeout)

}

func testWalletDeletePushSubscription() async {
let expectation = expectation(description: "expects to delete push subscription")
let uri = try! await dappPairingClient.create()
try! await walletPairingClient.pair(uri: uri)
try! await dappPushClient.request(account: Account.stub(), topic: uri.topic)
var subscriptionTopic: String!

walletPushClient.requestPublisher.sink { [unowned self] (id, _, _) in
Task(priority: .high) { try! await walletPushClient.approve(id: id, onSign: sign) }
}.store(in: &publishers)

dappPushClient.responsePublisher.sink { [unowned self] (_, result) in
guard case .success(let result) = result else {
XCTFail()
return
}
subscriptionTopic = result.pushSubscription.topic
Task(priority: .userInitiated) { try! await walletPushClient.deleteSubscription(topic: result.pushSubscription.topic)}
}.store(in: &publishers)

dappPushClient.deleteSubscriptionPublisher.sink { topic in
XCTAssertEqual(subscriptionTopic, topic)
expectation.fulfill()
}.store(in: &publishers)
wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}

func testDappDeletePushSubscription() async {
func testDeletePushSubscription() async {
let expectation = expectation(description: "expects to delete push subscription")
let uri = try! await dappPairingClient.create()
try! await walletPairingClient.pair(uri: uri)
try! await dappPushClient.request(account: Account.stub(), topic: uri.topic)
try! await dappPushClient.propose(account: Account.stub(), topic: uri.topic)
var subscriptionTopic: String!

walletPushClient.requestPublisher.sink { [unowned self] (id, _, _) in
Task(priority: .high) { try! await walletPushClient.approve(id: id, onSign: sign) }
}.store(in: &publishers)

dappPushClient.responsePublisher.sink { [unowned self] (_, result) in
guard case .success(let result) = result else {
dappPushClient.proposalResponsePublisher.sink { [unowned self] (result) in
guard case .success(let pushSubscription) = result else {
XCTFail()
return
}
subscriptionTopic = result.pushSubscription.topic
Task(priority: .userInitiated) { try! await dappPushClient.delete(topic: result.pushSubscription.topic)}
subscriptionTopic = pushSubscription.topic
Task(priority: .userInitiated) { try! await walletPushClient.deleteSubscription(topic: pushSubscription.topic)}
}.store(in: &publishers)

walletPushClient.deleteSubscriptionPublisher.sink { topic in
dappPushClient.deleteSubscriptionPublisher.sink { topic in
XCTAssertEqual(subscriptionTopic, topic)
expectation.fulfill()
}.store(in: &publishers)
wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}

// Push Subscribe
func testWalletCreatesSubscription() async {
let expectation = expectation(description: "expects to create push subscription")
let metadata = AppMetadata(name: "GM Dapp", description: "", url: "https://gm-dapp-xi.vercel.app/", icons: [])
try! await walletPushClient.subscribe(metadata: metadata, account: Account.stub(), onSign: sign)
walletPushClient.subscriptionsPublisher
.first()
.sink { [unowned self] subscriptions in
XCTAssertNotNil(subscriptions.first)
Task { try! await walletPushClient.deleteSubscription(topic: subscriptions.first!.topic) }
expectation.fulfill()
}.store(in: &publishers)
wait(for: [expectation], timeout: InputConfig.defaultTimeout)
}

func testWalletCreatesAndUpdatesSubscription() async {
let expectation = expectation(description: "expects to create and update push subscription")
let metadata = AppMetadata(name: "GM Dapp", description: "", url: "https://gm-dapp-xi.vercel.app/", icons: [])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ final class Web3InboxViewController: UIViewController {
private extension Web3InboxViewController {

func onSing(_ message: String) -> SigningResult {

let privateKey = Data(hex: importAccount.privateKey)
let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create()
let signature = try! signer.sign(message: message, privateKey: privateKey, type: .eip191)

return .signed(signature)
}
}
2 changes: 1 addition & 1 deletion Example/WalletApp/ApplicationLayer/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {

app.uri = connectionOptions.urlContexts.first?.url.absoluteString.replacingOccurrences(of: "walletapp://wc?uri=", with: "")

configurators.configure()
configurators.configure()
app.pushRegisterer.registerForPushNotifications()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension MainPresenter {
.receive(on: DispatchQueue.main)
.sink { [weak self] request in

// self?.router.present(pushRequest: request)
self?.router.present(pushRequest: request)
}.store(in: &disposeBag)

interactor.sessionProposalPublisher
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ final class MainRouter {
}

func present(pushRequest: PushRequest) {
PushRequestModule.create(app: app, pushRequest: pushRequest)
.presentFullScreen(from: viewController, transparentBackground: true)
// PushRequestModule.create(app: app, pushRequest: pushRequest)
Copy link
Contributor

Choose a reason for hiding this comment

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

method unused now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just want to showcase w3i capabilities and limitations for dogfooding. This presents a native screen.

// .presentFullScreen(from: viewController, transparentBackground: true)
}

init(app: Application) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ class DeletePushSubscriptionService {
}

func delete(topic: String) async throws {
let params = PushDeleteParams.userDisconnected
logger.debug("Will delete push subscription for reason: message: \(params.message) code: \(params.code), topic: \(topic)")
guard let _ = try? pushSubscriptionStore.get(key: topic)
else { throw Errors.pushSubscriptionNotFound}
let protocolMethod = PushDeleteProtocolMethod()
let params = PushDeleteParams.userDisconnected
logger.debug("Will delete push subscription for reason: message: \(params.message) code: \(params.code)")
pushSubscriptionStore.delete(forKey: topic)
pushMessagesDatabase?.deletePushMessages(topic: topic)
let request = RPCRequest(method: protocolMethod.method, params: params)
Expand Down
Loading