diff --git a/.github/actions/run_tests_without_building/action.yml b/.github/actions/run_tests_without_building/action.yml index a9639e3db..52c492e93 100644 --- a/.github/actions/run_tests_without_building/action.yml +++ b/.github/actions/run_tests_without_building/action.yml @@ -9,9 +9,13 @@ inputs: required: false default: 'relay.walletconnect.com' notify-endpoint: - description: 'The endpoint of the notify server e.g. cast.walletconnect.com' + description: 'The endpoint of the notify server e.g. notify.walletconnect.com' required: false - default: 'cast.walletconnect.com' + default: 'notify.walletconnect.com' + explorer-endpoint: + description: 'The endpoint of the explorer server e.g. explorer-api.walletconnect.com' + required: false + default: 'explorer-api.walletconnect.com' project-id: description: 'WalletConnect project id' required: true @@ -59,13 +63,13 @@ runs: - name: Run integration tests if: inputs.type == 'integration-tests' shell: bash - run: make integration_tests RELAY_HOST=${{ inputs.relay-endpoint }} PROJECT_ID=${{ inputs.project-id }} CAST_HOST=${{ inputs.notify-endpoint }} GM_DAPP_PROJECT_ID=${{ inputs.gm-dapp-project-id }} GM_DAPP_PROJECT_SECRET=${{ inputs.gm-dapp-project-secret }} GM_DAPP_HOST=${{ inputs.gm-dapp-host }} JS_CLIENT_API_HOST=${{ inputs.js-client-api-host }} + run: make integration_tests RELAY_HOST=${{ inputs.relay-endpoint }} PROJECT_ID=${{ inputs.project-id }} CAST_HOST=${{ inputs.notify-endpoint }} EXPLORER_HOST=${{ inputs.explorer-endpoint }} GM_DAPP_PROJECT_ID=${{ inputs.gm-dapp-project-id }} GM_DAPP_PROJECT_SECRET=${{ inputs.gm-dapp-project-secret }} GM_DAPP_HOST=${{ inputs.gm-dapp-host }} JS_CLIENT_API_HOST=${{ inputs.js-client-api-host }} # Relay Integration tests - name: Run Relay integration tests if: inputs.type == 'relay-tests' shell: bash - run: make relay_tests RELAY_HOST=${{ inputs.relay-endpoint }} PROJECT_ID=${{ inputs.project-id }} CAST_HOST=${{ inputs.notify-endpoint }} + run: make relay_tests RELAY_HOST=${{ inputs.relay-endpoint }} PROJECT_ID=${{ inputs.project-id }} CAST_HOST=${{ inputs.notify-endpoint }} EXPLORER_HOST=${{ inputs.explorer-endpoint }} # Smoke tests - name: Run smoke tests @@ -77,7 +81,7 @@ runs: - name: Run notify tests if: inputs.type == 'notify-tests' shell: bash - run: make notify_tests RELAY_HOST=${{ inputs.relay-endpoint }} PROJECT_ID=${{ inputs.project-id }} CAST_HOST=${{ inputs.notify-endpoint }} GM_DAPP_PROJECT_ID=${{ inputs.gm-dapp-project-id }} GM_DAPP_PROJECT_SECRET=${{ inputs.gm-dapp-project-secret }} GM_DAPP_HOST=${{ inputs.gm-dapp-host }} + run: make notify_tests RELAY_HOST=${{ inputs.relay-endpoint }} PROJECT_ID=${{ inputs.project-id }} CAST_HOST=${{ inputs.notify-endpoint }} EXPLORER_HOST=${{ inputs.explorer-endpoint }} GM_DAPP_PROJECT_ID=${{ inputs.gm-dapp-project-id }} GM_DAPP_PROJECT_SECRET=${{ inputs.gm-dapp-project-secret }} GM_DAPP_HOST=${{ inputs.gm-dapp-host }} - name: Run x-platform protocol tests if: inputs.type == 'x-platform-protocol-tests' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a9b07721..fe39b9775 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: - name: Run integration tests if: matrix.type == 'integration-tests' shell: bash - run: make integration_tests RELAY_HOST=relay.walletconnect.com PROJECT_ID=${{ secrets.PROJECT_ID }} CAST_HOST=notify.walletconnect.com GM_DAPP_PROJECT_ID=${{ secrets.GM_DAPP_PROJECT_ID }} GM_DAPP_PROJECT_SECRET=${{ secrets.GM_DAPP_PROJECT_SECRET }} GM_DAPP_HOST=gm.walletconnect.com JS_CLIENT_API_HOST=test-automation-api.walletconnect.com + run: make integration_tests RELAY_HOST=relay.walletconnect.com PROJECT_ID=${{ secrets.PROJECT_ID }} CAST_HOST=notify.walletconnect.com EXPLORER_HOST=explorer-api.walletconnect.com GM_DAPP_PROJECT_ID=${{ secrets.GM_DAPP_PROJECT_ID }} GM_DAPP_PROJECT_SECRET=${{ secrets.GM_DAPP_PROJECT_SECRET }} GM_DAPP_HOST=gm.walletconnect.com JS_CLIENT_API_HOST=test-automation-api.walletconnect.com # Relay Integration tests - name: Run Relay integration tests diff --git a/Configuration.xcconfig b/Configuration.xcconfig index 98daaddd4..890889577 100644 --- a/Configuration.xcconfig +++ b/Configuration.xcconfig @@ -1,5 +1,9 @@ RELAY_HOST = relay.walletconnect.com +CAST_HOST = notify.walletconnect.com + +EXPLORER_HOST = explorer-api.walletconnect.com + // Uncomment next line and paste your project id. Get this on: https://cloud.walletconnect.com/sign-in // PROJECT_ID = YOUR_PROJECT_ID @@ -18,5 +22,3 @@ RELAY_HOST = relay.walletconnect.com // WALLETAPP_SENTRY_DSN = WALLETAPP_SENTRY_DSN // MIXPANEL_TOKEN = MIXPANEL_TOKEN - -CAST_HOST = notify.walletconnect.com diff --git a/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan b/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan index e3aa93b52..40b79df1d 100644 --- a/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan +++ b/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan @@ -15,6 +15,10 @@ "key" : "RELAY_HOST", "value" : "$(RELAY_HOST)" }, + { + "key" : "EXPLORER_HOST", + "value" : "$(EXPLORER_HOST)" + }, { "key" : "GM_DAPP_HOST", "value" : "$(GM_DAPP_HOST)" diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 0b8a898c9..4cecf980f 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -305,6 +305,13 @@ C5F32A322954816C00A6476E /* ConnectionDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */; }; C5F32A342954817600A6476E /* ConnectionDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A332954817600A6476E /* ConnectionDetailsView.swift */; }; C5F32A362954FE3C00A6476E /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C5F32A352954FE3C00A6476E /* Colors.xcassets */; }; + C5FFEA762ADD8956007282A2 /* BrowserModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA752ADD8956007282A2 /* BrowserModule.swift */; }; + C5FFEA782ADD896E007282A2 /* BrowserPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA772ADD896E007282A2 /* BrowserPresenter.swift */; }; + C5FFEA7A2ADD8974007282A2 /* BrowserRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA792ADD8974007282A2 /* BrowserRouter.swift */; }; + C5FFEA7C2ADD897C007282A2 /* BrowserInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA7B2ADD897C007282A2 /* BrowserInteractor.swift */; }; + C5FFEA7E2ADD8985007282A2 /* BrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA7D2ADD8985007282A2 /* BrowserView.swift */; }; + C5FFEA812ADDACD7007282A2 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA802ADDACD7007282A2 /* WebView.swift */; }; + C5FFEA842ADDAD6D007282A2 /* SafariViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FFEA832ADDAD6D007282A2 /* SafariViewController.swift */; }; CF1A594529E5876600AAC16B /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1A593A29E5876600AAC16B /* XCUIElement.swift */; }; CF1A594629E5876600AAC16B /* PushNotificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1A593C29E5876600AAC16B /* PushNotificationTests.swift */; }; CF1A594829E5876600AAC16B /* Engine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1A593F29E5876600AAC16B /* Engine.swift */; }; @@ -634,6 +641,13 @@ C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsPresenter.swift; sourceTree = ""; }; C5F32A332954817600A6476E /* ConnectionDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsView.swift; sourceTree = ""; }; C5F32A352954FE3C00A6476E /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; + C5FFEA752ADD8956007282A2 /* BrowserModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserModule.swift; sourceTree = ""; }; + C5FFEA772ADD896E007282A2 /* BrowserPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserPresenter.swift; sourceTree = ""; }; + C5FFEA792ADD8974007282A2 /* BrowserRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserRouter.swift; sourceTree = ""; }; + C5FFEA7B2ADD897C007282A2 /* BrowserInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserInteractor.swift; sourceTree = ""; }; + C5FFEA7D2ADD8985007282A2 /* BrowserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserView.swift; sourceTree = ""; }; + C5FFEA802ADDACD7007282A2 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; + C5FFEA832ADDAD6D007282A2 /* SafariViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariViewController.swift; sourceTree = ""; }; CF1A593029E5873D00AAC16B /* EchoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EchoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CF1A593A29E5876600AAC16B /* XCUIElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; CF1A593C29E5876600AAC16B /* PushNotificationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationTests.swift; sourceTree = ""; }; @@ -1606,6 +1620,7 @@ C56EE229293F5668004840D1 /* Wallet */ = { isa = PBXGroup; children = ( + C5FFEA742ADD8942007282A2 /* Browser */, A50D53BB2ABA053600A4FD8B /* NotifySettings */, A51811992A52E82100A52B15 /* Settings */, 847BD1DB2989493F00076C90 /* Main */, @@ -1799,6 +1814,36 @@ path = ConnectionDetails; sourceTree = ""; }; + C5FFEA742ADD8942007282A2 /* Browser */ = { + isa = PBXGroup; + children = ( + C5FFEA822ADDAD5B007282A2 /* SafariViewController */, + C5FFEA7F2ADDACCC007282A2 /* WebView */, + C5FFEA752ADD8956007282A2 /* BrowserModule.swift */, + C5FFEA772ADD896E007282A2 /* BrowserPresenter.swift */, + C5FFEA792ADD8974007282A2 /* BrowserRouter.swift */, + C5FFEA7B2ADD897C007282A2 /* BrowserInteractor.swift */, + C5FFEA7D2ADD8985007282A2 /* BrowserView.swift */, + ); + path = Browser; + sourceTree = ""; + }; + C5FFEA7F2ADDACCC007282A2 /* WebView */ = { + isa = PBXGroup; + children = ( + C5FFEA802ADDACD7007282A2 /* WebView.swift */, + ); + path = WebView; + sourceTree = ""; + }; + C5FFEA822ADDAD5B007282A2 /* SafariViewController */ = { + isa = PBXGroup; + children = ( + C5FFEA832ADDAD6D007282A2 /* SafariViewController.swift */, + ); + path = SafariViewController; + sourceTree = ""; + }; CF1A593129E5873D00AAC16B /* EchoUITests */ = { isa = PBXGroup; children = ( @@ -2384,6 +2429,7 @@ 847BD1E4298A806800076C90 /* NotificationsModule.swift in Sources */, C55D348C295DD8CA0004314A /* PasteUriInteractor.swift in Sources */, 847BD1D92989492500076C90 /* MainPresenter.swift in Sources */, + C5FFEA842ADDAD6D007282A2 /* SafariViewController.swift in Sources */, C55D3497295DFA750004314A /* WelcomeView.swift in Sources */, A57879722A4F225E00F8D10B /* ImportAccount.swift in Sources */, C5B2F71029705827000DBA0E /* EthereumTransaction.swift in Sources */, @@ -2415,6 +2461,7 @@ C56EE243293F566D004840D1 /* ScanView.swift in Sources */, 84310D05298BC980000C15B6 /* MainInteractor.swift in Sources */, C56EE288293F5757004840D1 /* ThirdPartyConfigurator.swift in Sources */, + C5FFEA7E2ADD8985007282A2 /* BrowserView.swift in Sources */, 847BD1D62989492500076C90 /* MainViewController.swift in Sources */, C5B2F6FA29705293000DBA0E /* SessionRequestInteractor.swift in Sources */, C55D34AE2965FB750004314A /* SessionProposalModule.swift in Sources */, @@ -2435,9 +2482,12 @@ A5B4F7C32ABB20AE0099AF7C /* SubscriptionInteractor.swift in Sources */, A50D53C52ABA055700A4FD8B /* NotifyPreferencesView.swift in Sources */, C56EE246293F566D004840D1 /* ScanRouter.swift in Sources */, + C5FFEA7A2ADD8974007282A2 /* BrowserRouter.swift in Sources */, C55D3481295DD7140004314A /* AuthRequestRouter.swift in Sources */, + C5FFEA812ADDACD7007282A2 /* WebView.swift in Sources */, C5B2F6F829705293000DBA0E /* SessionRequestView.swift in Sources */, C56EE28C293F5757004840D1 /* Configurator.swift in Sources */, + C5FFEA782ADD896E007282A2 /* BrowserPresenter.swift in Sources */, C55D3489295DD8CA0004314A /* PasteUriModule.swift in Sources */, C55D3494295DFA750004314A /* WelcomePresenter.swift in Sources */, C5B2F6F929705293000DBA0E /* SessionRequestPresenter.swift in Sources */, @@ -2456,11 +2506,13 @@ C55D3496295DFA750004314A /* WelcomeInteractor.swift in Sources */, C5B2F6FC297055B0000DBA0E /* SOLSigner.swift in Sources */, A518119F2A52E83100A52B15 /* SettingsModule.swift in Sources */, + C5FFEA7C2ADD897C007282A2 /* BrowserInteractor.swift in Sources */, 8487A9482A83AD680003D5AF /* LoggingService.swift in Sources */, C55D348D295DD8CA0004314A /* PasteUriView.swift in Sources */, C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */, C56EE249293F566D004840D1 /* ScanInteractor.swift in Sources */, C56EE28A293F5757004840D1 /* AppDelegate.swift in Sources */, + C5FFEA762ADD8956007282A2 /* BrowserModule.swift in Sources */, C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */, C5B2F6F629705293000DBA0E /* SessionRequestModule.swift in Sources */, C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */, diff --git a/Example/IntegrationTests/Push/NotifyTests.swift b/Example/IntegrationTests/Push/NotifyTests.swift index a0bfed40e..97edfdd0a 100644 --- a/Example/IntegrationTests/Push/NotifyTests.swift +++ b/Example/IntegrationTests/Push/NotifyTests.swift @@ -74,7 +74,8 @@ final class NotifyTests: XCTestCase { keychainStorage: keychain, environment: .sandbox) let keyserverURL = URL(string: "https://keys.walletconnect.com")! - let client = NotifyClientFactory.create(projectId: InputConfig.projectId, + // Note:- prod project_id do not exists on staging, we can use gmDappProjectId + let client = NotifyClientFactory.create(projectId: InputConfig.gmDappProjectId, keyserverURL: keyserverURL, logger: notifyLogger, keyValueStorage: keyValueStorage, @@ -84,7 +85,8 @@ final class NotifyTests: XCTestCase { pairingRegisterer: pairingClient, pushClient: pushClient, crypto: DefaultCryptoProvider(), - notifyHost: InputConfig.notifyHost) + notifyHost: InputConfig.notifyHost, + explorerHost: InputConfig.explorerHost) return client } @@ -152,19 +154,25 @@ final class NotifyTests: XCTestCase { func testWalletCreatesAndUpdatesSubscription() async { let expectation = expectation(description: "expects to create and update notify subscription") - let updateScope: Set = ["8529aae8-cb26-4d49-922e-eb099044bebe"] expectation.assertForOverFulfill = false + var updateScope: Set! var didUpdate = false + walletNotifyClientA.subscriptionsPublisher .sink { [unowned self] subscriptions in - guard let subscription = subscriptions.first else { return } + guard + let subscription = subscriptions.first, + let scope = subscription.scope.keys.first + else { return } + let updatedScope = Set(subscription.scope.filter { $0.value.enabled == true }.keys) if !didUpdate { + updateScope = Set([scope]) didUpdate = true Task(priority: .high) { - try await walletNotifyClientA.update(topic: subscription.topic, scope: updateScope) + try await walletNotifyClientA.update(topic: subscription.topic, scope: Set([scope])) } } if updateScope == updatedScope { @@ -184,17 +192,26 @@ final class NotifyTests: XCTestCase { func testNotifyServerSubscribeAndNotifies() async throws { let subscribeExpectation = expectation(description: "creates notify subscription") let messageExpectation = expectation(description: "receives a notify message") - let notifyMessage = NotifyMessage.stub(type: "8529aae8-cb26-4d49-922e-eb099044bebe") + + var notifyMessage: NotifyMessage! var didNotify = false walletNotifyClientA.subscriptionsPublisher .sink { subscriptions in - guard let subscription = subscriptions.first else { return } + guard + let subscription = subscriptions.first, + let scope = subscription.scope.keys.first + else { return } + let notifier = Publisher() if !didNotify { didNotify = true + + let message = NotifyMessage.stub(type: scope) + notifyMessage = message + Task(priority: .high) { - try await notifier.notify(topic: subscription.topic, account: subscription.account, message: notifyMessage) + try await notifier.notify(topic: subscription.topic, account: subscription.account, message: message) subscribeExpectation.fulfill() } } @@ -202,7 +219,7 @@ final class NotifyTests: XCTestCase { walletNotifyClientA.notifyMessagePublisher .sink { [unowned self] notifyMessageRecord in - XCTAssertEqual(notifyMessage, notifyMessageRecord.message) + XCTAssertEqual(notifyMessageRecord.message, notifyMessage) Task(priority: .high) { try await walletNotifyClientA.deleteSubscription(topic: notifyMessageRecord.topic) diff --git a/Example/Shared/Tests/InputConfig.swift b/Example/Shared/Tests/InputConfig.swift index b420b93b8..761e19788 100644 --- a/Example/Shared/Tests/InputConfig.swift +++ b/Example/Shared/Tests/InputConfig.swift @@ -26,6 +26,10 @@ struct InputConfig { return config(for: "CAST_HOST")! } + static var explorerHost: String { + return config(for: "EXPLORER_HOST")! + } + static var relayUrl: String { return "wss://\(relayHost)" } diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserInteractor.swift new file mode 100644 index 000000000..3134e266e --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserInteractor.swift @@ -0,0 +1,3 @@ +final class BrowserInteractor { + +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserModule.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserModule.swift new file mode 100644 index 000000000..bcbd6240f --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserModule.swift @@ -0,0 +1,16 @@ +import SwiftUI + +final class BrowserModule { + @discardableResult + static func create(app: Application) -> UIViewController { + let router = BrowserRouter(app: app) + let interactor = BrowserInteractor() + let presenter = BrowserPresenter(interactor: interactor, router: router) + let view = BrowserView().environmentObject(presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserPresenter.swift new file mode 100644 index 000000000..a3ffcc4cc --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserPresenter.swift @@ -0,0 +1,62 @@ +import UIKit +import Combine +import WebKit + +import WalletConnectNetworking + +final class BrowserPresenter: ObservableObject { + private let interactor: BrowserInteractor + private let router: BrowserRouter + + weak var webView: WKWebView? + + @Published var urlString = "https://react-app.walletconnect.com" + + private var disposeBag = Set() + + init(interactor: BrowserInteractor, router: BrowserRouter) { + defer { setupInitialState() } + self.interactor = interactor + self.router = router + } + + func loadURLString() { + if let url = URL(string: urlString) { + webView?.load(URLRequest(url: url.sanitise)) + } + } + + func reload() { + webView?.reload() + } +} + +// MARK: SceneViewModel +extension BrowserPresenter: SceneViewModel { + var sceneTitle: String? { + return "Browser" + } + + var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { + return .always + } +} + +// MARK: Privates +private extension BrowserPresenter { + func setupInitialState() { + + } +} + +extension URL { + var sanitise: URL { + if var components = URLComponents(url: self, resolvingAgainstBaseURL: false) { + if components.scheme == nil { + components.scheme = "https" + } + return components.url ?? self + } + return self + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserRouter.swift new file mode 100644 index 000000000..e0b1d5883 --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserRouter.swift @@ -0,0 +1,15 @@ +import UIKit + +final class BrowserRouter { + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } + + func presentWelcome() { + BrowserModule.create(app: app).present() + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserView.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserView.swift new file mode 100644 index 000000000..082bd420c --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/BrowserView.swift @@ -0,0 +1,66 @@ +import SwiftUI + +struct BrowserView: View { + @EnvironmentObject var viewModel: BrowserPresenter + + @State private var selectedBrowser = 0 + + var body: some View { + VStack { + Picker("", selection: $selectedBrowser) { + Text("WKWebView").tag(0) + Text("SafariViewController").tag(1) + } + .pickerStyle(.segmented) + .padding() + + ZStack { + if selectedBrowser == 0 { + VStack { + HStack { + TextField( + viewModel.urlString, + text: $viewModel.urlString + ) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .onSubmit { + viewModel.loadURLString() + } + + Button { + viewModel.reload() + } label: { + Image(systemName: "arrow.clockwise") + } + } + .padding(.horizontal) + + Divider() + .padding(.top) + + if let url = URL(string: viewModel.urlString) { + WebView(url: url, viewModel: viewModel) + } + + Spacer() + } + .onAppear { + viewModel.loadURLString() + } + } else { + if let url = URL(string: viewModel.urlString) { + SafariWebView(url: url.sanitise) + } + } + } + } + } +} + +#if DEBUG +struct BrowserView_Previews: PreviewProvider { + static var previews: some View { + BrowserView() + } +} +#endif diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/SafariViewController/SafariViewController.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/SafariViewController/SafariViewController.swift new file mode 100644 index 000000000..16844098e --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/SafariViewController/SafariViewController.swift @@ -0,0 +1,14 @@ +import SwiftUI +import SafariServices + +struct SafariWebView: UIViewControllerRepresentable { + let url: URL + + func makeUIViewController(context: Context) -> SFSafariViewController { + return SFSafariViewController(url: url) + } + + func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) { + + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/Browser/WebView/WebView.swift b/Example/WalletApp/PresentationLayer/Wallet/Browser/WebView/WebView.swift new file mode 100644 index 000000000..a78105312 --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/Browser/WebView/WebView.swift @@ -0,0 +1,19 @@ +import SwiftUI +import WebKit + +struct WebView: UIViewRepresentable { + let url: URL + + @ObservedObject var viewModel: BrowserPresenter + + func makeUIView(context: Context) -> WKWebView { + let webView = WKWebView() + viewModel.webView = webView + webView.load(URLRequest(url: url)) + return webView + } + + func updateUIView(_ uiView: WKWebView, context: Context) { + + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/Main/MainPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Main/MainPresenter.swift index 762bdf97c..451cce287 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Main/MainPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Main/MainPresenter.swift @@ -17,6 +17,7 @@ final class MainPresenter { return [ router.walletViewController(importAccount: importAccount), router.notificationsViewController(importAccount: importAccount), + router.browserViewController(), router.settingsViewController() ] } diff --git a/Example/WalletApp/PresentationLayer/Wallet/Main/MainRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/Main/MainRouter.swift index 211a1fc62..6e67c078c 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Main/MainRouter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Main/MainRouter.swift @@ -27,6 +27,11 @@ final class MainRouter { .wrapToNavigationController() } + func browserViewController() -> UIViewController { + return BrowserModule.create(app: app) + .wrapToNavigationController() + } + func present(proposal: Session.Proposal, importAccount: ImportAccount, context: VerifyContext?) { SessionProposalModule.create(app: app, importAccount: importAccount, proposal: proposal, context: context) .presentFullScreen(from: viewController, transparentBackground: true) diff --git a/Example/WalletApp/PresentationLayer/Wallet/Main/Model/TabPage.swift b/Example/WalletApp/PresentationLayer/Wallet/Main/Model/TabPage.swift index 4dd01cfe5..d79c5a4e4 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Main/Model/TabPage.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Main/Model/TabPage.swift @@ -3,6 +3,7 @@ import UIKit enum TabPage: CaseIterable { case wallet case notifications + case browser case settings var title: String { @@ -13,6 +14,8 @@ enum TabPage: CaseIterable { return "Notifications" case .settings: return "Settings" + case .browser: + return "Browser" } } @@ -22,6 +25,8 @@ enum TabPage: CaseIterable { return UIImage(systemName: "house.fill")! case .notifications: return UIImage(systemName: "bell.fill")! + case .browser: + return UIImage(systemName: "network")! case .settings: return UIImage(systemName: "gearshape.fill")! } @@ -32,6 +37,6 @@ enum TabPage: CaseIterable { } static var enabledTabs: [TabPage] { - return [.wallet, .notifications, .settings] + return [.wallet, .notifications, .browser, .settings] } } diff --git a/Makefile b/Makefile index 32cdfdd66..68c9b1a0b 100755 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ build_all: RELAY_HOST='$(RELAY_HOST)' \ PROJECT_ID='$(PROJECT_ID)' \ CAST_HOST='$(CAST_HOST)' \ + EXPLORER_HOST='$(EXPLORER_HOST)' \ JS_CLIENT_API_HOST='$(JS_CLIENT_API_HOST)' \ build-for-testing \ | xcbeautify diff --git a/NotifyTests.xctestplan b/NotifyTests.xctestplan index 881dd5fda..fe598450b 100644 --- a/NotifyTests.xctestplan +++ b/NotifyTests.xctestplan @@ -15,6 +15,10 @@ "key" : "RELAY_HOST", "value" : "$(RELAY_HOST)" }, + { + "key" : "EXPLORER_HOST", + "value" : "$(EXPLORER_HOST)" + }, { "key" : "GM_DAPP_HOST", "value" : "$(GM_DAPP_HOST)" diff --git a/Sources/WalletConnectModal/WalletConnectModal.swift b/Sources/WalletConnectModal/WalletConnectModal.swift index 7fe3c3674..87085fcf5 100644 --- a/Sources/WalletConnectModal/WalletConnectModal.swift +++ b/Sources/WalletConnectModal/WalletConnectModal.swift @@ -89,7 +89,11 @@ extension WalletConnectModal { let modal = WalletConnectModalSheetController() vc.present(modal, animated: true) } - + + public static func create() -> UIViewController { + return WalletConnectModalSheetController() + } + private static func topViewController(_ base: UIViewController? = nil) -> UIViewController? { let base = base ?? UIApplication diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift index 8fac80ce5..f04b62a14 100644 --- a/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift +++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift @@ -2,7 +2,7 @@ import Foundation public struct NotifyClientFactory { - public static func create(projectId: String, groupIdentifier: String, networkInteractor: NetworkInteracting, pairingRegisterer: PairingRegisterer, pushClient: PushClient, crypto: CryptoProvider, notifyHost: String) -> NotifyClient { + public static func create(projectId: String, groupIdentifier: String, networkInteractor: NetworkInteracting, pairingRegisterer: PairingRegisterer, pushClient: PushClient, crypto: CryptoProvider, notifyHost: String, explorerHost: String) -> NotifyClient { let logger = ConsoleLogger(prefix: "🔔",loggingLevel: .debug) let keyValueStorage = UserDefaults.standard let keyserverURL = URL(string: "https://keys.walletconnect.com")! @@ -20,7 +20,8 @@ public struct NotifyClientFactory { pairingRegisterer: pairingRegisterer, pushClient: pushClient, crypto: crypto, - notifyHost: notifyHost + notifyHost: notifyHost, + explorerHost: explorerHost ) } @@ -35,7 +36,8 @@ public struct NotifyClientFactory { pairingRegisterer: PairingRegisterer, pushClient: PushClient, crypto: CryptoProvider, - notifyHost: String + notifyHost: String, + explorerHost: String ) -> NotifyClient { let kms = KeyManagementService(keychain: keychainStorage) let subscriptionStore = KeyedDatabase(storage: keyValueStorage, identifier: NotifyStorageIdntifiers.notifySubscription) @@ -48,7 +50,7 @@ public struct NotifyClientFactory { let deleteNotifySubscriptionRequester = DeleteNotifySubscriptionRequester(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, webDidResolver: webDidResolver, kms: kms, logger: logger, notifyStorage: notifyStorage) let resubscribeService = NotifyResubscribeService(networkInteractor: networkInteractor, notifyStorage: notifyStorage, logger: logger) - let notifyConfigProvider = NotifyConfigProvider(projectId: projectId) + let notifyConfigProvider = NotifyConfigProvider(projectId: projectId, explorerHost: explorerHost) let notifySubscribeRequester = NotifySubscribeRequester(keyserverURL: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, logger: logger, kms: kms, webDidResolver: webDidResolver, notifyConfigProvider: notifyConfigProvider) diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyConfig.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyConfig.swift index b0e88b181..f9579ba6c 100644 --- a/Sources/WalletConnectNotify/Client/Wallet/NotifyConfig.swift +++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyConfig.swift @@ -13,7 +13,7 @@ struct NotifyConfig: Codable { } let id: String let name: String - let homepage: String + let homepage: String? let description: String let dapp_url: String let image_url: ImageUrl? diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyConfigProvider.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyConfigProvider.swift index 8b196f592..414d7960d 100644 --- a/Sources/WalletConnectNotify/Client/Wallet/NotifyConfigProvider.swift +++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyConfigProvider.swift @@ -3,11 +3,13 @@ import Foundation actor NotifyConfigProvider { private let projectId: String + private let explorerHost: String private var cache: [String: NotifyConfig] = [:] - init(projectId: String) { + init(projectId: String, explorerHost: String) { self.projectId = projectId + self.explorerHost = explorerHost } func resolveNotifyConfig(appDomain: String) async -> NotifyConfig { @@ -16,7 +18,7 @@ actor NotifyConfigProvider { } do { - let httpClient = HTTPNetworkClient(host: "explorer-api.walletconnect.com") + let httpClient = HTTPNetworkClient(host: explorerHost) let request = NotifyConfigAPI.notifyDApps(projectId: projectId, appDomain: appDomain) let response = try await httpClient.request(NotifyConfigResponse.self, at: request) let config = response.data diff --git a/Sources/WalletConnectNotify/Notify+Config.swift b/Sources/WalletConnectNotify/Notify+Config.swift index c7e699c03..4d1141022 100644 --- a/Sources/WalletConnectNotify/Notify+Config.swift +++ b/Sources/WalletConnectNotify/Notify+Config.swift @@ -7,5 +7,6 @@ extension Notify { let environment: APNSEnvironment let crypto: CryptoProvider let notifyHost: String + let explorerHost: String } } diff --git a/Sources/WalletConnectNotify/Notify.swift b/Sources/WalletConnectNotify/Notify.swift index 039c139d6..2880d2ce5 100644 --- a/Sources/WalletConnectNotify/Notify.swift +++ b/Sources/WalletConnectNotify/Notify.swift @@ -13,7 +13,8 @@ public class Notify { pairingRegisterer: Pair.registerer, pushClient: Push.instance, crypto: config.crypto, - notifyHost: config.notifyHost + notifyHost: config.notifyHost, + explorerHost: config.explorerHost ) }() @@ -22,8 +23,15 @@ public class Notify { private init() { } /// Wallet's configuration method - static public func configure(pushHost: String = "echo.walletconnect.com", groupIdentifier: String, environment: APNSEnvironment, crypto: CryptoProvider, notifyHost: String = "notify.walletconnect.com") { - Notify.config = Notify.Config(pushHost: pushHost, groupIdentifier: groupIdentifier, environment: environment, crypto: crypto, notifyHost: notifyHost) + static public func configure( + pushHost: String = "echo.walletconnect.com", + groupIdentifier: String, + environment: APNSEnvironment, + crypto: CryptoProvider, + notifyHost: String = "notify.walletconnect.com", + explorerHost: String = "explorer-api.walletconnect.com" + ) { + Notify.config = Notify.Config(pushHost: pushHost, groupIdentifier: groupIdentifier, environment: environment, crypto: crypto, notifyHost: notifyHost, explorerHost: explorerHost) } } diff --git a/Sources/WalletConnectRelay/Dispatching.swift b/Sources/WalletConnectRelay/Dispatching.swift index e9d15ac3d..bf3ef2c92 100644 --- a/Sources/WalletConnectRelay/Dispatching.swift +++ b/Sources/WalletConnectRelay/Dispatching.swift @@ -43,6 +43,9 @@ final class Dispatcher: NSObject, Dispatching { let socket = socketFactory.create(with: relayUrlFactory.create(fallback: fallback)) socket.request.addValue(EnvironmentInfo.userAgent, forHTTPHeaderField: "User-Agent") + if let bundleId = Bundle.main.bundleIdentifier { + socket.request.addValue(bundleId, forHTTPHeaderField: "Origin") + } self.socket = socket switch socketConnectionType { diff --git a/Sources/WalletConnectRelay/PackageConfig.json b/Sources/WalletConnectRelay/PackageConfig.json index 52e73e014..7db8bf6cc 100644 --- a/Sources/WalletConnectRelay/PackageConfig.json +++ b/Sources/WalletConnectRelay/PackageConfig.json @@ -1 +1 @@ -{"version": "1.9.0"} +{"version": "1.9.1"} diff --git a/Sources/WalletConnectSign/Sign/SignClientProtocol.swift b/Sources/WalletConnectSign/Sign/SignClientProtocol.swift index 437c115c6..95f56ee76 100644 --- a/Sources/WalletConnectSign/Sign/SignClientProtocol.swift +++ b/Sources/WalletConnectSign/Sign/SignClientProtocol.swift @@ -10,6 +10,7 @@ public protocol SignClientProtocol { var sessionDeletePublisher: AnyPublisher<(String, Reason), Never> { get } var sessionResponsePublisher: AnyPublisher { get } var sessionRejectionPublisher: AnyPublisher<(Session.Proposal, Reason), Never> { get } + var sessionEventPublisher: AnyPublisher<(event: Session.Event, sessionTopic: String, chainId: Blockchain?), Never> { get } func connect(requiredNamespaces: [String: ProposalNamespace], optionalNamespaces: [String: ProposalNamespace]?, sessionProperties: [String: String]?, topic: String) async throws func request(params: Request) async throws diff --git a/Tests/Web3WalletTests/Mocks/SignClientMock.swift b/Tests/Web3WalletTests/Mocks/SignClientMock.swift index 3d5cca9fe..62ba27489 100644 --- a/Tests/Web3WalletTests/Mocks/SignClientMock.swift +++ b/Tests/Web3WalletTests/Mocks/SignClientMock.swift @@ -59,6 +59,17 @@ final class SignClientMock: SignClientProtocol { .eraseToAnyPublisher() } + var sessionEventPublisher: AnyPublisher<(event: WalletConnectSign.Session.Event, sessionTopic: String, chainId: WalletConnectUtils.Blockchain?), Never> { + return Result.Publisher( + ( + WalletConnectSign.Session.Event(name: "chainChanged", data: AnyCodable("event_data")), + "topic", + Blockchain("eip155:1") + ) + ) + .eraseToAnyPublisher() + } + var sessionRejectionPublisher: AnyPublisher<(Session.Proposal, Reason), Never> { let sessionProposal = Session.Proposal( id: "", diff --git a/run_tests.sh b/run_tests.sh index ea5cad206..b6b1911d7 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -86,6 +86,7 @@ else update_xctestrun --key "GM_DAPP_PROJECT_SECRET" --value "$GM_DAPP_PROJECT_SECRET" --target "$XCTESTRUN" update_xctestrun --key "GM_DAPP_HOST" --value "$GM_DAPP_HOST" --target "$XCTESTRUN" update_xctestrun --key "CAST_HOST" --value "$CAST_HOST" --target "$XCTESTRUN" + update_xctestrun --key "EXPLORER_HOST" --value "$EXPLORER_HOST" --target "$XCTESTRUN" update_xctestrun --key "JS_CLIENT_API_HOST" --value "$JS_CLIENT_API_HOST" --target "$XCTESTRUN" (